| 1 | //
 | 
|---|
| 2 | // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
 | 
|---|
| 3 | //
 | 
|---|
| 4 | // The contents of this file are covered under the licence agreement in the
 | 
|---|
| 5 | // file "LICENCE" distributed with Cforall.
 | 
|---|
| 6 | //
 | 
|---|
| 7 | // Lvalue.cpp -- Clean up lvalues and remove references.
 | 
|---|
| 8 | //
 | 
|---|
| 9 | // Author           : Andrew Beach
 | 
|---|
| 10 | // Created On       : Thu Sep 15 14:08:00 2022
 | 
|---|
| 11 | // Last Modified By : Andrew Beach
 | 
|---|
| 12 | // Last Modified On : Wed Oct  6  9:59:00 2022
 | 
|---|
| 13 | // Update Count     : 0
 | 
|---|
| 14 | //
 | 
|---|
| 15 | 
 | 
|---|
| 16 | #include "Lvalue.h"
 | 
|---|
| 17 | 
 | 
|---|
| 18 | #include <set>
 | 
|---|
| 19 | #include <iostream>
 | 
|---|
| 20 | 
 | 
|---|
| 21 | #include "AST/Copy.hpp"                // for deepCopy
 | 
|---|
| 22 | #include "AST/Expr.hpp"
 | 
|---|
| 23 | #include "AST/Inspect.hpp"
 | 
|---|
| 24 | #include "AST/LinkageSpec.hpp"         // for Linkage
 | 
|---|
| 25 | #include "AST/Pass.hpp"
 | 
|---|
| 26 | #include "Common/SemanticError.h"      // for SemanticWarning
 | 
|---|
| 27 | #include "Common/ToString.hpp"         // for toCString
 | 
|---|
| 28 | #include "Common/UniqueName.h"         // for UniqueName
 | 
|---|
| 29 | #include "GenPoly/GenPoly.h"           // for genFunctionType
 | 
|---|
| 30 | #include "ResolvExpr/typeops.h"        // for typesCompatible
 | 
|---|
| 31 | #include "ResolvExpr/Unify.h"          // for unify
 | 
|---|
| 32 | 
 | 
|---|
| 33 | #if 0
 | 
|---|
| 34 | #define PRINT(x) x
 | 
|---|
| 35 | #else
 | 
|---|
| 36 | #define PRINT(x)
 | 
|---|
| 37 | #endif
 | 
|---|
| 38 | 
 | 
|---|
| 39 | namespace GenPoly {
 | 
|---|
| 40 | 
 | 
|---|
| 41 | namespace {
 | 
|---|
| 42 | 
 | 
|---|
| 43 | /// Intrinsic functions that return references now instead return lvalues.
 | 
|---|
| 44 | struct FixIntrinsicResults final : public ast::WithGuards {
 | 
|---|
| 45 |         enum {
 | 
|---|
| 46 |                 NoSkip,
 | 
|---|
| 47 |                 Skip,
 | 
|---|
| 48 |                 SkipInProgress,
 | 
|---|
| 49 |         } skip = NoSkip;
 | 
|---|
| 50 | 
 | 
|---|
| 51 |         void previsit( ast::AsmExpr const * ) {
 | 
|---|
| 52 |                 GuardValue( skip ) = Skip;
 | 
|---|
| 53 |         }
 | 
|---|
| 54 |         void previsit( ast::ApplicationExpr const * ) {
 | 
|---|
| 55 |                 GuardValue( skip ) = (skip == Skip) ? SkipInProgress : NoSkip;
 | 
|---|
| 56 |         }
 | 
|---|
| 57 | 
 | 
|---|
| 58 |         ast::Expr const * postvisit( ast::ApplicationExpr const * expr );
 | 
|---|
| 59 |         void previsit( ast::FunctionDecl const * decl );
 | 
|---|
| 60 |         bool inIntrinsic = false;
 | 
|---|
| 61 | };
 | 
|---|
| 62 | 
 | 
|---|
| 63 | /// Add de-references around address-of operations on reference types.
 | 
|---|
| 64 | struct AddressRef final :
 | 
|---|
| 65 |                 public ast::WithConstTranslationUnit,
 | 
|---|
| 66 |                 public ast::WithGuards,
 | 
|---|
| 67 |                 public ast::WithShortCircuiting,
 | 
|---|
| 68 |                 public ast::WithVisitorRef<AddressRef> {
 | 
|---|
| 69 |         void previsit( ast::AddressExpr const * expr );
 | 
|---|
| 70 |         ast::Expr const * postvisit( ast::AddressExpr const * expr );
 | 
|---|
| 71 |         void previsit( ast::Expr const * expr );
 | 
|---|
| 72 |         ast::ApplicationExpr const * previsit( ast::ApplicationExpr const * expr );
 | 
|---|
| 73 |         void previsit( ast::SingleInit const * init );
 | 
|---|
| 74 | 
 | 
|---|
| 75 |         void handleNonAddr( ast::Expr const * expr );
 | 
|---|
| 76 | 
 | 
|---|
| 77 |         bool first = true;
 | 
|---|
| 78 |         bool current = false;
 | 
|---|
| 79 |         bool addCast = false;
 | 
|---|
| 80 |         int refDepth = 0;
 | 
|---|
| 81 | };
 | 
|---|
| 82 | 
 | 
|---|
| 83 | /// Handles casts between references and pointers,
 | 
|---|
| 84 | /// creating temporaries for the conversion.
 | 
|---|
| 85 | struct ReferenceConversions final :
 | 
|---|
| 86 |                 public ast::WithConstTranslationUnit,
 | 
|---|
| 87 |                 public ast::WithGuards, public ast::WithStmtsToAdd<> {
 | 
|---|
| 88 |         ast::Expr const * postvisit( ast::CastExpr const * expr );
 | 
|---|
| 89 |         ast::Expr const * postvisit( ast::AddressExpr const * expr );
 | 
|---|
| 90 | };
 | 
|---|
| 91 | 
 | 
|---|
| 92 | /// Intrinsic functions that take reference parameters don't actually do.
 | 
|---|
| 93 | /// Their reference arguments must be implicity dereferenced.
 | 
|---|
| 94 | /// TODO Also appears to contain redundent code with AddressRef
 | 
|---|
| 95 | struct FixIntrinsicArgs final :
 | 
|---|
| 96 |                 public ast::WithConstTranslationUnit {
 | 
|---|
| 97 |         ast::Expr const * postvisit( ast::ApplicationExpr const * expr );
 | 
|---|
| 98 | };
 | 
|---|
| 99 | 
 | 
|---|
| 100 | /// Removes redundant &* / *& patterns that may be generated.
 | 
|---|
| 101 | struct CollapseAddressDeref final {
 | 
|---|
| 102 |         ast::Expr const * postvisit( ast::AddressExpr const * expr );
 | 
|---|
| 103 |         ast::Expr const * postvisit( ast::ApplicationExpr const * expr );
 | 
|---|
| 104 | };
 | 
|---|
| 105 | 
 | 
|---|
| 106 | /// GCC-like Generalized Lvalues (which have since been removed from GCC).
 | 
|---|
| 107 | /// https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Lvalues.html#Lvalues
 | 
|---|
| 108 | /// Replaces &(a,b) with (a, &b), &(a ? b : c) with (a ? &b : &c)
 | 
|---|
| 109 | struct GeneralizedLvalue final :
 | 
|---|
| 110 |                 public ast::WithVisitorRef<GeneralizedLvalue> {
 | 
|---|
| 111 |         ast::Expr const * postvisit( ast::AddressExpr const * expr );
 | 
|---|
| 112 |         ast::Expr const * postvisit( ast::MemberExpr const * expr );
 | 
|---|
| 113 | 
 | 
|---|
| 114 |         template<typename Node, typename Func>
 | 
|---|
| 115 |         ast::Expr const * applyTransformation(
 | 
|---|
| 116 |               Node const * expr, ast::ptr<ast::Expr> Node::*field, Func mkExpr );
 | 
|---|
| 117 | };
 | 
|---|
| 118 | 
 | 
|---|
| 119 | /// Replace all reference types with pointer types.
 | 
|---|
| 120 | struct ReferenceTypeElimination final {
 | 
|---|
| 121 |         ast::Type const * postvisit( ast::ReferenceType const * type );
 | 
|---|
| 122 | };
 | 
|---|
| 123 | 
 | 
|---|
| 124 | /// True for intrinsic function calls that return an lvalue in C.
 | 
|---|
| 125 | bool isIntrinsicReference( ast::Expr const * expr ) {
 | 
|---|
| 126 |         // The known intrinsic-reference prelude functions.
 | 
|---|
| 127 |         static std::set<std::string> const lvalueFunctions = { "*?", "?[?]" };
 | 
|---|
| 128 |         if ( auto untyped = dynamic_cast<ast::UntypedExpr const *>( expr ) ) {
 | 
|---|
| 129 |                 std::string fname = ast::getFunctionName( untyped );
 | 
|---|
| 130 |                 return lvalueFunctions.count( fname );
 | 
|---|
| 131 |         } else if ( auto app = dynamic_cast<ast::ApplicationExpr const *>( expr ) ) {
 | 
|---|
| 132 |                 if ( auto func = ast::getFunction( app ) ) {
 | 
|---|
| 133 |                         return func->linkage == ast::Linkage::Intrinsic
 | 
|---|
| 134 |                                 && lvalueFunctions.count( func->name );
 | 
|---|
| 135 |                 }
 | 
|---|
| 136 |         }
 | 
|---|
| 137 |         return false;
 | 
|---|
| 138 | }
 | 
|---|
| 139 | 
 | 
|---|
| 140 | bool isGeneratedInstrinct( ast::Expr const * expr ) {
 | 
|---|
| 141 |         if ( auto app = dynamic_cast<ast::ApplicationExpr const *>( expr ) ) {
 | 
|---|
| 142 |                 if ( app->args.size() == 2 && ast::getFunction( app )->name == "?[?]" ) {
 | 
|---|
| 143 |                         auto param_1 = dynamic_cast<ast::VariableExpr const *>(app->args.front().get());
 | 
|---|
| 144 |                         if ( param_1 ) {
 | 
|---|
| 145 |                                 auto param_1_as_obj = param_1->var.as<ast::ObjectDecl>();
 | 
|---|
| 146 |                                 return ( param_1_as_obj->name.find( "values_") != std::string::npos
 | 
|---|
| 147 |                                         ||  param_1_as_obj->name.find( "labels_" ) != std::string::npos );
 | 
|---|
| 148 |                         }
 | 
|---|
| 149 |                 }
 | 
|---|
| 150 |         }
 | 
|---|
| 151 |         return false;
 | 
|---|
| 152 | }
 | 
|---|
| 153 | 
 | 
|---|
| 154 | // A maybe typed variant of the createDeref function (only UntypedExpr).
 | 
|---|
| 155 | ast::Expr * mkDeref(
 | 
|---|
| 156 |                 ast::TranslationGlobal const & global, ast::Expr const * arg ) {
 | 
|---|
| 157 |         if ( global.dereference ) {
 | 
|---|
| 158 |                 // Note: Reference depth can be arbitrarily deep here,
 | 
|---|
| 159 |                 // so peel off the outermost pointer/reference, not just
 | 
|---|
| 160 |                 // pointer because they are effecitvely equivalent in this pass
 | 
|---|
| 161 |                 ast::VariableExpr * deref = new ast::VariableExpr(
 | 
|---|
| 162 |                         arg->location, global.dereference );
 | 
|---|
| 163 |                 deref->result = new ast::PointerType( deref->result );
 | 
|---|
| 164 |                 ast::Type const * base = ast::getPointerBase( arg->result );
 | 
|---|
| 165 |                 assertf( base, "expected pointer type in dereference (type was %s)", toString( arg->result ).c_str() );
 | 
|---|
| 166 |                 ast::ApplicationExpr * ret =
 | 
|---|
| 167 |                         new ast::ApplicationExpr( arg->location, deref, { arg } );
 | 
|---|
| 168 |                 ret->result = ast::deepCopy( base );
 | 
|---|
| 169 |                 return ret;
 | 
|---|
| 170 |         } else {
 | 
|---|
| 171 |                 return ast::UntypedExpr::createDeref( arg->location, arg );
 | 
|---|
| 172 |         }
 | 
|---|
| 173 | }
 | 
|---|
| 174 | 
 | 
|---|
| 175 | ast::Expr const * FixIntrinsicResults::postvisit(
 | 
|---|
| 176 |                 ast::ApplicationExpr const * expr ) {
 | 
|---|
| 177 | 
 | 
|---|
| 178 |         if ( skip == SkipInProgress || !isIntrinsicReference( expr ) || isGeneratedInstrinct( expr ) ) {
 | 
|---|
| 179 |                 return expr;
 | 
|---|
| 180 |         }
 | 
|---|
| 181 |         // Eliminate reference types from intrinsic applications
 | 
|---|
| 182 |         // now they return lvalues.
 | 
|---|
| 183 |         ast::ptr<ast::ReferenceType> result =
 | 
|---|
| 184 |                         expr->result.strict_as<ast::ReferenceType>();
 | 
|---|
| 185 |         expr = ast::mutate_field( expr, &ast::ApplicationExpr::result,
 | 
|---|
| 186 |                         ast::deepCopy( result->base ) );
 | 
|---|
| 187 |         if ( inIntrinsic ) {
 | 
|---|
| 188 |                 return expr;
 | 
|---|
| 189 |         }
 | 
|---|
| 190 |         // When not in an intrinsic function, add a cast to don't add cast when
 | 
|---|
| 191 |         // in an intrinsic function, since they already have the cast.
 | 
|---|
| 192 |         auto * ret = new ast::CastExpr( expr->location, expr, result.get() );
 | 
|---|
| 193 |         ret->env = expr->env;
 | 
|---|
| 194 |         return ret;
 | 
|---|
| 195 | }
 | 
|---|
| 196 | 
 | 
|---|
| 197 | void FixIntrinsicResults::previsit( ast::FunctionDecl const * decl ) {
 | 
|---|
| 198 |         GuardValue( inIntrinsic ) = decl->linkage == ast::Linkage::Intrinsic;
 | 
|---|
| 199 | }
 | 
|---|
| 200 | 
 | 
|---|
| 201 | void AddressRef::previsit( ast::AddressExpr const * ) {
 | 
|---|
| 202 |         // Is this the first address-of in the chain?
 | 
|---|
| 203 |         GuardValue( current ) = first;
 | 
|---|
| 204 |         // Later references will not be for next address-of to be first in chain.
 | 
|---|
| 205 |         GuardValue( first ) = false;
 | 
|---|
| 206 |         // If is the outermost address-of in a chain:
 | 
|---|
| 207 |         if ( current ) {
 | 
|---|
| 208 |                 // Set depth to 0 so that postvisit can
 | 
|---|
| 209 |                 // find the innermost address-of easily.
 | 
|---|
| 210 |                 GuardValue( refDepth ) = 0;
 | 
|---|
| 211 |         }
 | 
|---|
| 212 | }
 | 
|---|
| 213 | 
 | 
|---|
| 214 | ast::Expr const * AddressRef::postvisit( ast::AddressExpr const * expr ) {
 | 
|---|
| 215 |         PRINT( std::cerr << "addr ref at " << expr << std::endl; )
 | 
|---|
| 216 |         if ( 0 == refDepth ) {
 | 
|---|
| 217 |                 PRINT( std::cerr << "depth 0, get new depth..." << std::endl; )
 | 
|---|
| 218 |                 // Is this the innermost address-of in a chain? record depth D.
 | 
|---|
| 219 |                 if ( isIntrinsicReference( expr->arg ) ) {
 | 
|---|
| 220 |                         assertf( false, "AddrRef : address-of should not have intrinsic reference argument: %s", toCString( expr->arg )  );
 | 
|---|
| 221 |                 } else {
 | 
|---|
| 222 |                         // try to avoid ?[?]
 | 
|---|
| 223 |                         // TODO is this condition still necessary? intrinsicReferences
 | 
|---|
| 224 |                         // should have a cast around them at this point, so I don't think
 | 
|---|
| 225 |                         // this condition ever fires.
 | 
|---|
| 226 |                         refDepth = expr->arg->result->referenceDepth();
 | 
|---|
| 227 |                         PRINT( std::cerr << "arg not intrinsic reference, new depth is: " << refDepth << std::endl; )
 | 
|---|
| 228 |                 }
 | 
|---|
| 229 |         }
 | 
|---|
| 230 |         if ( current ) {
 | 
|---|
| 231 |                 PRINT( std::cerr << "current, depth is: " << refDepth << std::endl; )
 | 
|---|
| 232 |                 ast::Expr const * ret = expr;
 | 
|---|
| 233 |                 while ( refDepth ) {
 | 
|---|
| 234 |                         // Add one dereference for each address-of in the chain.
 | 
|---|
| 235 |                         ret = mkDeref( transUnit().global, ret );
 | 
|---|
| 236 |                         --refDepth;
 | 
|---|
| 237 |                 }
 | 
|---|
| 238 | 
 | 
|---|
| 239 |                 // if addrExpr depth is 0, then the result is a pointer because the
 | 
|---|
| 240 |                 // arg was depth 1 and not lvalue. This means the dereference result
 | 
|---|
| 241 |                 // is not a reference, is lvalue, and one less pointer depth than the
 | 
|---|
| 242 |                 // addrExpr. Thus the cast is meaningless.
 | 
|---|
| 243 |                 // TODO: One thing to double check is whether it is possible for the
 | 
|---|
| 244 |                 // types to differ outside of the single pointer level (i.e. can the
 | 
|---|
| 245 |                 // base type of addrExpr differ from the type of addrExpr-arg?). If
 | 
|---|
| 246 |                 // so then the cast might need to be added, conditional on a more
 | 
|---|
| 247 |                 // sophisticated check.
 | 
|---|
| 248 |                 if ( addCast && 0 != expr->result->referenceDepth() ) {
 | 
|---|
| 249 |                         PRINT( std::cerr << "adding cast to " << expr->result << std::endl; )
 | 
|---|
| 250 |                         return new ast::CastExpr( expr->location,
 | 
|---|
| 251 |                                 ret, ast::deepCopy( expr->result ) );
 | 
|---|
| 252 |                 }
 | 
|---|
| 253 |                 return ret;
 | 
|---|
| 254 |         }
 | 
|---|
| 255 |         PRINT( std::cerr << "not current..." << std::endl; )
 | 
|---|
| 256 |         return expr;
 | 
|---|
| 257 | }
 | 
|---|
| 258 | 
 | 
|---|
| 259 | void AddressRef::previsit( ast::Expr const * expr ) {
 | 
|---|
| 260 |         handleNonAddr( expr );
 | 
|---|
| 261 |         GuardValue( addCast ) = false;
 | 
|---|
| 262 | }
 | 
|---|
| 263 | 
 | 
|---|
| 264 | // So we want to skip traversing to the head?
 | 
|---|
| 265 | ast::ApplicationExpr const * AddressRef::previsit(
 | 
|---|
| 266 |                 ast::ApplicationExpr const * expr ) {
 | 
|---|
| 267 |         visit_children = false;
 | 
|---|
| 268 |         GuardValue( addCast );
 | 
|---|
| 269 |         handleNonAddr( expr );
 | 
|---|
| 270 |         auto mutExpr = ast::mutate( expr );
 | 
|---|
| 271 |         for ( ast::ptr<ast::Expr> & arg : mutExpr->args ) {
 | 
|---|
| 272 |                 addCast = true;
 | 
|---|
| 273 |                 arg = arg->accept( *visitor );
 | 
|---|
| 274 |         }
 | 
|---|
| 275 |         return mutExpr;
 | 
|---|
| 276 | }
 | 
|---|
| 277 | 
 | 
|---|
| 278 | void AddressRef::previsit( ast::SingleInit const * ) {
 | 
|---|
| 279 |         // Each initialization context with address-of requires a cast.
 | 
|---|
| 280 |         GuardValue( addCast ) = true;
 | 
|---|
| 281 | }
 | 
|---|
| 282 | 
 | 
|---|
| 283 | // idea: &&&E: get outer &, inner &
 | 
|---|
| 284 | // at inner &, record depth D of reference type of argument of &.
 | 
|---|
| 285 | // at auter &, add D derefs.
 | 
|---|
| 286 | void AddressRef::handleNonAddr( ast::Expr const * ) {
 | 
|---|
| 287 |         // non-address-of: reset status variables:
 | 
|---|
| 288 |         // * current expr is NOT the first address-of expr in an address-of chain.
 | 
|---|
| 289 |         // * next seen address-of expr IS the first in the chain.
 | 
|---|
| 290 |         GuardValue( current ) = false;
 | 
|---|
| 291 |         GuardValue( first ) = true;
 | 
|---|
| 292 | }
 | 
|---|
| 293 | 
 | 
|---|
| 294 | ast::Expr const * ReferenceConversions::postvisit(
 | 
|---|
| 295 |                 ast::CastExpr const * expr ) {
 | 
|---|
| 296 |         // TODO: Is it possible to convert directly between reference types with
 | 
|---|
| 297 |         // a different base. e.g.
 | 
|---|
| 298 |         //   int x;
 | 
|---|
| 299 |         //   (double&)x;
 | 
|---|
| 300 |         // At the moment, I (who?) am working off of the assumption that this is
 | 
|---|
| 301 |         // illegal, thus the cast becomes redundant after this pass, so trash the
 | 
|---|
| 302 |         // cast altogether. If that changes, care must be taken to insert the
 | 
|---|
| 303 |         // correct pointer casts in the right places.
 | 
|---|
| 304 | 
 | 
|---|
| 305 |         // Note: reference depth difference is the determining factor in what
 | 
|---|
| 306 |         // code is run, rather than whether something is reference type or not,
 | 
|---|
| 307 |         // since conversion still needs to occur when both types are references
 | 
|---|
| 308 |         // that differ in depth.
 | 
|---|
| 309 |         ast::Type const * dstType = expr->result.get();
 | 
|---|
| 310 |         ast::Type const * srcType = expr->arg->result.get();
 | 
|---|
| 311 |         assertf( dstType, "Cast to no type in: %s", toCString( expr ) );
 | 
|---|
| 312 |         assertf( srcType, "Cast from no type in: %s", toCString( expr ) );
 | 
|---|
| 313 |         int dstDepth = dstType->referenceDepth();
 | 
|---|
| 314 |         int srcDepth = srcType->referenceDepth();
 | 
|---|
| 315 |         int diff = dstDepth - srcDepth;
 | 
|---|
| 316 | 
 | 
|---|
| 317 |         if ( 0 < diff && !expr->arg->get_lvalue() ) {
 | 
|---|
| 318 |                 // rvalue to reference conversion -- introduce temporary
 | 
|---|
| 319 |                 // know that reference depth of cast argument is 0
 | 
|---|
| 320 |                 //   (int &&&)3;
 | 
|---|
| 321 |                 // becomes
 | 
|---|
| 322 |                 //   int __ref_tmp_0 = 3;
 | 
|---|
| 323 |                 //   int & __ref_tmp_1 = &__ref_tmp_0;
 | 
|---|
| 324 |                 //   int && __ref_tmp_2 = &__ref_tmp_1;
 | 
|---|
| 325 |                 //   &__ref_tmp_2;
 | 
|---|
| 326 |                 // The last & comes from the remaining reference conversion code.
 | 
|---|
| 327 |                 SemanticWarning( expr->arg->location,
 | 
|---|
| 328 |                         Warning::RvalueToReferenceConversion, toCString( expr->arg ) );
 | 
|---|
| 329 | 
 | 
|---|
| 330 |                 static UniqueName tmpNamer( "__ref_tmp_" );
 | 
|---|
| 331 |                 ast::ObjectDecl * tmp = new ast::ObjectDecl( expr->arg->location,
 | 
|---|
| 332 |                         tmpNamer.newName(),
 | 
|---|
| 333 |                         ast::deepCopy( expr->arg->result ),
 | 
|---|
| 334 |                         new ast::SingleInit( expr->arg->location, expr->arg ) );
 | 
|---|
| 335 |                 PRINT( std::cerr << "make tmp: " << tmp << std::endl; )
 | 
|---|
| 336 |                 stmtsToAddBefore.push_back( new ast::DeclStmt( tmp->location, tmp ) );
 | 
|---|
| 337 |                 for ( int i = 0 ; i < dstDepth - 1 ; ++i ) {
 | 
|---|
| 338 |                         ast::ObjectDecl * newTmp = new ast::ObjectDecl( tmp->location,
 | 
|---|
| 339 |                                 tmpNamer.newName(),
 | 
|---|
| 340 |                                 new ast::ReferenceType( ast::deepCopy( tmp->type ) ),
 | 
|---|
| 341 |                                 new ast::SingleInit( tmp->location,
 | 
|---|
| 342 |                                         new ast::AddressExpr( tmp->location,
 | 
|---|
| 343 |                                                 new ast::VariableExpr( tmp->location, tmp ) ) ) );
 | 
|---|
| 344 |                         PRINT( std::cerr << "make tmp: " << i << ": " << newTmp << std::endl; )
 | 
|---|
| 345 |                         stmtsToAddBefore.push_back(
 | 
|---|
| 346 |                                 new ast::DeclStmt( newTmp->location, newTmp ) );
 | 
|---|
| 347 |                         tmp = newTmp;
 | 
|---|
| 348 |                 }
 | 
|---|
| 349 |                 // Update diff so that remaining code works out correctly.
 | 
|---|
| 350 |                 expr = ast::mutate_field( expr, &ast::CastExpr::arg,
 | 
|---|
| 351 |                         new ast::VariableExpr( tmp->location, tmp ) );
 | 
|---|
| 352 |                 PRINT( std::cerr << "update cast to: " << expr << std::endl; )
 | 
|---|
| 353 |                 srcType = expr->arg->result;
 | 
|---|
| 354 |                 srcDepth = srcType->referenceDepth();
 | 
|---|
| 355 |                 diff = dstDepth - srcDepth;
 | 
|---|
| 356 |                 assert( 1 == diff );
 | 
|---|
| 357 |         }
 | 
|---|
| 358 | 
 | 
|---|
| 359 |         // Handle conversion between different depths.
 | 
|---|
| 360 |         PRINT(
 | 
|---|
| 361 |                 if ( dstDepth || srcDepth ) {
 | 
|---|
| 362 |                         std::cerr << "dstType: " << dstType << " / srcType: " << srcType << '\n';
 | 
|---|
| 363 |                         std::cerr << "depth: " << dstDepth << " / " << srcDepth << std::endl;
 | 
|---|
| 364 |                 }
 | 
|---|
| 365 |         )
 | 
|---|
| 366 |         // Conversion to type with more depth/more references.
 | 
|---|
| 367 |         // Add address-of for each level of difference.
 | 
|---|
| 368 |         if ( 0 < diff ) {
 | 
|---|
| 369 |                 ast::Expr * ret = ast::mutate( expr->arg.get() );
 | 
|---|
| 370 |                 for ( int i = 0 ; i < diff ; ++i ) {
 | 
|---|
| 371 |                         ret = new ast::AddressExpr( ret->location, ret );
 | 
|---|
| 372 |                 }
 | 
|---|
| 373 |                 if ( expr->arg->get_lvalue() &&
 | 
|---|
| 374 |                                 !ResolvExpr::typesCompatible(
 | 
|---|
| 375 |                                         srcType,
 | 
|---|
| 376 |                                         strict_dynamic_cast<ast::ReferenceType const *>( dstType )->base ) ) {
 | 
|---|
| 377 |                         // Must keep cast if cast-to type is different from the actual type.
 | 
|---|
| 378 |                         return ast::mutate_field( expr, &ast::CastExpr::arg, ret );
 | 
|---|
| 379 |                 }
 | 
|---|
| 380 |                 ret->env = expr->env;
 | 
|---|
| 381 |                 ret->result = expr->result;
 | 
|---|
| 382 |                 return ret;
 | 
|---|
| 383 |         // Conversion to type with less depth/fewer references.
 | 
|---|
| 384 |         // Add dereferences for each level of difference.
 | 
|---|
| 385 |         } else if ( diff < 0 ) {
 | 
|---|
| 386 |                 ast::Expr * ret = ast::mutate( expr->arg.get() );
 | 
|---|
| 387 |                 for ( int i = 0 ; i < -diff ; ++i ) {
 | 
|---|
| 388 |                         ret = mkDeref( transUnit().global, ret );
 | 
|---|
| 389 |                 }
 | 
|---|
| 390 |                 // Must keep cast if types are different.
 | 
|---|
| 391 |                 if ( !ResolvExpr::typesCompatibleIgnoreQualifiers(
 | 
|---|
| 392 |                                 dstType->stripReferences(),
 | 
|---|
| 393 |                                 srcType->stripReferences() ) ) {
 | 
|---|
| 394 |                         return ast::mutate_field( expr, &ast::CastExpr::arg, ret );
 | 
|---|
| 395 |                 }
 | 
|---|
| 396 |                 ret->env = expr->env;
 | 
|---|
| 397 |                 ret->result = expr->result;
 | 
|---|
| 398 |                 // The result must be an lvalue.
 | 
|---|
| 399 |                 assert( ret->get_lvalue() );
 | 
|---|
| 400 |                 return ret;
 | 
|---|
| 401 |         // Conversion with the same depth.
 | 
|---|
| 402 |         } else {
 | 
|---|
| 403 |                 assert( 0 == diff );
 | 
|---|
| 404 |                 // Remove useless generated casts.
 | 
|---|
| 405 |                 if ( expr->isGenerated &&
 | 
|---|
| 406 |                                 ResolvExpr::typesCompatible(
 | 
|---|
| 407 |                                         expr->result,
 | 
|---|
| 408 |                                         expr->arg->result ) ) {
 | 
|---|
| 409 |                         PRINT(
 | 
|---|
| 410 |                                 std::cerr << "types are compatible, removing cast: " << expr << '\n';
 | 
|---|
| 411 |                                 std::cerr << "-- " << expr->result << '\n';
 | 
|---|
| 412 |                                 std::cerr << "-- " << expr->arg->result << std::endl;
 | 
|---|
| 413 |                         )
 | 
|---|
| 414 |                         return ast::mutate_field( expr->arg.get(),
 | 
|---|
| 415 |                                         &ast::Expr::env, expr->env.get() );
 | 
|---|
| 416 |                 }
 | 
|---|
| 417 |                 return expr;
 | 
|---|
| 418 |         }
 | 
|---|
| 419 | }
 | 
|---|
| 420 | 
 | 
|---|
| 421 | ast::Expr const * ReferenceConversions::postvisit(
 | 
|---|
| 422 |                 ast::AddressExpr const * expr ) {
 | 
|---|
| 423 |         // Inner expression may have been lvalue to reference conversion, which
 | 
|---|
| 424 |         // becomes an address expression. In this case, remove the outer address
 | 
|---|
| 425 |         // expression and return the argument.
 | 
|---|
| 426 |         // TODO: It's possible that this might catch too much and require a more
 | 
|---|
| 427 |         // sophisticated check. TODO What check are we talking about here?
 | 
|---|
| 428 |         return expr;
 | 
|---|
| 429 | }
 | 
|---|
| 430 | 
 | 
|---|
| 431 | ast::Expr const * FixIntrinsicArgs::postvisit(
 | 
|---|
| 432 |                 ast::ApplicationExpr const * expr ) {
 | 
|---|
| 433 |         // Intrinsic functions don't really take reference-typed parameters,
 | 
|---|
| 434 |         // so they require an implicit dereference on their arguments.
 | 
|---|
| 435 |         auto function = ast::getFunction( expr );
 | 
|---|
| 436 |         if ( function == nullptr ) {
 | 
|---|
| 437 |                 return expr;
 | 
|---|
| 438 |         }
 | 
|---|
| 439 | 
 | 
|---|
| 440 |         ast::FunctionType const * ftype = GenPoly::getFunctionType( function->get_type() );
 | 
|---|
| 441 |         assertf( ftype, "Function declaration does not have function type." );
 | 
|---|
| 442 |         // Can be of different lengths only when function is variadic.
 | 
|---|
| 443 |         assertf( ftype->params.size() == expr->args.size() || ftype->isVarArgs,
 | 
|---|
| 444 |                 "ApplicationExpr args do not match formal parameter type." );
 | 
|---|
| 445 |         assertf( ftype->params.size() <= expr->args.size(),
 | 
|---|
| 446 |                 "Cannot have more parameters than arguments." );
 | 
|---|
| 447 | 
 | 
|---|
| 448 |         unsigned int i = 0;
 | 
|---|
| 449 |         unsigned int const end = ftype->params.size();
 | 
|---|
| 450 | 
 | 
|---|
| 451 |         // This is used to make sure we get a zip on shortests.
 | 
|---|
| 452 |         if ( end == i ) return expr;
 | 
|---|
| 453 | 
 | 
|---|
| 454 |         // This mutate could be redundent, but it is simpler this way.
 | 
|---|
| 455 |         auto mutExpr = ast::mutate( expr );
 | 
|---|
| 456 | 
 | 
|---|
| 457 |         for ( auto pair : unsafe_group_iterate( mutExpr->args, ftype->params ) ) {
 | 
|---|
| 458 |                 ast::ptr<ast::Expr> & arg = std::get<0>( pair );
 | 
|---|
| 459 |                 ast::ptr<ast::Type> const & formal = std::get<1>( pair );
 | 
|---|
| 460 |                 PRINT(
 | 
|---|
| 461 |                         std::cerr << "pair<0>: " << arg.get() << std::endl;
 | 
|---|
| 462 |                         std::cerr << " -- " << arg->result << std::endl;
 | 
|---|
| 463 |                         std::cerr << "pair<1>: " << formal << std::endl;
 | 
|---|
| 464 |                 )
 | 
|---|
| 465 |                 //if ( dynamic_cast<ast::ReferenceType const *>( formal.get() ) ) {
 | 
|---|
| 466 |                 if ( formal.as<ast::ReferenceType>() ) {
 | 
|---|
| 467 |                         PRINT( std::cerr << "===formal is reference" << std::endl; )
 | 
|---|
| 468 |                         // TODO: It's likely that the second condition should be
 | 
|---|
| 469 |                         // `... && ! isIntrinsicReference( arg )`, but this requires
 | 
|---|
| 470 |                         // investigation.
 | 
|---|
| 471 | 
 | 
|---|
| 472 |                         if ( ast::Linkage::Intrinsic != function->linkage
 | 
|---|
| 473 |                                         && isIntrinsicReference( arg ) ) {
 | 
|---|
| 474 |                                 // Needed for definition of prelude functions, etc.
 | 
|---|
| 475 |                                 // If argument is dereference or array subscript, the result
 | 
|---|
| 476 |                                 // isn't REALLY a reference, but non-intrinsic functions
 | 
|---|
| 477 |                                 // expect a reference: take address
 | 
|---|
| 478 | 
 | 
|---|
| 479 |                                 // TODO: OK, so this should be cut?!
 | 
|---|
| 480 |                                 // NODE: Previously, this condition fixed
 | 
|---|
| 481 |                                 //   void f(int *&);
 | 
|---|
| 482 |                                 //   int & x = ...;
 | 
|---|
| 483 |                                 //   f(&x);
 | 
|---|
| 484 |                                 // But now this is taken care of by a reference cast added by
 | 
|---|
| 485 |                                 // AddressRef. Need to find a new example or remove this
 | 
|---|
| 486 |                                 // branch.
 | 
|---|
| 487 |                                 PRINT(
 | 
|---|
| 488 |                                         std::cerr << "===is intrinsic arg in non-intrinsic call - adding address" << std::endl;
 | 
|---|
| 489 |                                 )
 | 
|---|
| 490 |                                 arg = new ast::AddressExpr( arg->location, arg );
 | 
|---|
| 491 |                         } else if ( ast::Linkage::Intrinsic == function->linkage
 | 
|---|
| 492 |                                         && arg->result->referenceDepth() != 0 ) {
 | 
|---|
| 493 |                                 // Argument is a 'real' reference, but function expects a C
 | 
|---|
| 494 |                                 // lvalue: Add a dereference to the reference-typed argument.
 | 
|---|
| 495 |                                 PRINT(
 | 
|---|
| 496 |                                         std::cerr << "===is non-intrinsic arg in intrinsic call - adding deref to arg" << std::endl;
 | 
|---|
| 497 |                                 )
 | 
|---|
| 498 |                                 ast::Type const * base = ast::getPointerBase( arg->result );
 | 
|---|
| 499 |                                 assertf( base, "parameter is reference, arg must be pointer or reference: %s", toString( arg->result ).c_str() );
 | 
|---|
| 500 |                                 ast::PointerType * ptr = new ast::PointerType( ast::deepCopy( base ) );
 | 
|---|
| 501 |                                 arg = ast::mutate_field( arg.get(),
 | 
|---|
| 502 |                                                 &ast::ApplicationExpr::result, ptr );
 | 
|---|
| 503 |                                 arg = mkDeref( transUnit().global, arg );
 | 
|---|
| 504 |                         }
 | 
|---|
| 505 |                 }
 | 
|---|
| 506 |                 ++i;
 | 
|---|
| 507 |                 if ( end == i ) break;
 | 
|---|
| 508 |         }
 | 
|---|
| 509 |         return mutExpr;
 | 
|---|
| 510 | }
 | 
|---|
| 511 | 
 | 
|---|
| 512 | ast::Expr const * CollapseAddressDeref::postvisit(
 | 
|---|
| 513 |                 ast::AddressExpr const * expr ) {
 | 
|---|
| 514 |         ast::Expr const * arg = expr->arg;
 | 
|---|
| 515 |         if ( isIntrinsicReference( arg ) ) {
 | 
|---|
| 516 |                 std::string fname = ast::getFunctionName( arg );
 | 
|---|
| 517 |                 if ( fname == "*?" ) {
 | 
|---|
| 518 |                         ast::Expr const * arg0 = ast::getCallArg( arg, 0 );
 | 
|---|
| 519 |                         ast::Expr * ret = ast::mutate( arg0 );
 | 
|---|
| 520 |                         ret->env = expr->env;
 | 
|---|
| 521 |                         return ret;
 | 
|---|
| 522 |                 }
 | 
|---|
| 523 |         } else if ( auto cast = dynamic_cast<ast::CastExpr const *>( arg ) ) {
 | 
|---|
| 524 |                 // Need to move cast to pointer type out a level since address of
 | 
|---|
| 525 |                 // pointer is not valid C code (can be introduced in prior passes,
 | 
|---|
| 526 |                 // e.g., InstantiateGeneric)
 | 
|---|
| 527 |                 if ( ast::getPointerBase( cast->result ) ) {
 | 
|---|
| 528 |                         auto mutExpr = ast::mutate( expr );
 | 
|---|
| 529 |                         auto mutCast = strict_dynamic_cast<ast::CastExpr *>(
 | 
|---|
| 530 |                                         ast::mutate( mutExpr->arg.release() ) );
 | 
|---|
| 531 |                         mutExpr->arg = mutCast->arg;
 | 
|---|
| 532 |                         mutCast->arg = mutExpr;
 | 
|---|
| 533 |                         mutCast->result = new ast::PointerType( mutCast->result );
 | 
|---|
| 534 |                         return mutCast;
 | 
|---|
| 535 |                 }
 | 
|---|
| 536 |         }
 | 
|---|
| 537 |         return expr;
 | 
|---|
| 538 | }
 | 
|---|
| 539 | 
 | 
|---|
| 540 | ast::Expr const * CollapseAddressDeref::postvisit(
 | 
|---|
| 541 |                 ast::ApplicationExpr const * expr ) {
 | 
|---|
| 542 |         if ( isIntrinsicReference( expr ) ) {
 | 
|---|
| 543 |                 std::string fname = ast::getFunctionName( expr );
 | 
|---|
| 544 |                 if ( fname == "*?" ) {
 | 
|---|
| 545 |                         assert( 1 == expr->args.size() );
 | 
|---|
| 546 |                         ast::Expr const * arg = ast::getCallArg( expr, 0 );
 | 
|---|
| 547 |                         // xxx - this isn't right, because it can remove casts that
 | 
|---|
| 548 |                         // should be there...
 | 
|---|
| 549 |                         //      while ( auto cast = dynamic_cast< ast::CastExpr const * >( arg ) ) {
 | 
|---|
| 550 |                         //              arg = cast->arg;
 | 
|---|
| 551 |                         //      }
 | 
|---|
| 552 |                         if ( auto addr = dynamic_cast<ast::AddressExpr const *>( arg ) ) {
 | 
|---|
| 553 |                                 return ast::mutate_field( addr->arg.get(),
 | 
|---|
| 554 |                                                 &ast::Expr::env, expr->env.get() );
 | 
|---|
| 555 |                         }
 | 
|---|
| 556 |                 }
 | 
|---|
| 557 |         }
 | 
|---|
| 558 |         return expr;
 | 
|---|
| 559 | }
 | 
|---|
| 560 | 
 | 
|---|
| 561 | ast::Expr const * GeneralizedLvalue::postvisit(
 | 
|---|
| 562 |                 ast::AddressExpr const * expr ) {
 | 
|---|
| 563 |         return applyTransformation( expr, &ast::AddressExpr::arg,
 | 
|---|
| 564 |                 []( ast::Expr const * arg ) {
 | 
|---|
| 565 |                         return new ast::AddressExpr( arg->location, arg );
 | 
|---|
| 566 |                 }
 | 
|---|
| 567 |         );
 | 
|---|
| 568 | }
 | 
|---|
| 569 | 
 | 
|---|
| 570 | ast::Expr const * GeneralizedLvalue::postvisit(
 | 
|---|
| 571 |                 ast::MemberExpr const * expr ) {
 | 
|---|
| 572 |         return applyTransformation( expr, &ast::MemberExpr::aggregate,
 | 
|---|
| 573 |                 [expr]( ast::Expr const * aggr ) {
 | 
|---|
| 574 |                         return new ast::MemberExpr( aggr->location, expr->member, aggr );
 | 
|---|
| 575 |                 }
 | 
|---|
| 576 |         );
 | 
|---|
| 577 | }
 | 
|---|
| 578 | 
 | 
|---|
| 579 | template<typename Node, typename Func>
 | 
|---|
| 580 | ast::Expr const * GeneralizedLvalue::applyTransformation(
 | 
|---|
| 581 |                 Node const * expr, ast::ptr<ast::Expr> Node::*field, Func mkExpr ) {
 | 
|---|
| 582 |         ast::ptr<ast::Expr> const & arg = expr->*field;
 | 
|---|
| 583 |         if ( auto commaArg = arg.as<ast::CommaExpr>() ) {
 | 
|---|
| 584 |                 ast::Expr const * arg1 = ast::deepCopy( commaArg->arg1 );
 | 
|---|
| 585 |                 ast::Expr const * arg2 = ast::deepCopy( commaArg->arg2 );
 | 
|---|
| 586 |                 ast::Expr const * ret = new ast::CommaExpr(
 | 
|---|
| 587 |                         commaArg->location, arg1, mkExpr( arg2 )->accept( *visitor ) );
 | 
|---|
| 588 |                 return ret;
 | 
|---|
| 589 |         } else if ( auto condArg = arg.as<ast::ConditionalExpr>() ) {
 | 
|---|
| 590 |                 ast::Expr const * arg1 = ast::deepCopy( condArg->arg1 );
 | 
|---|
| 591 |                 ast::Expr const * arg2 = ast::deepCopy( condArg->arg2 );
 | 
|---|
| 592 |                 ast::Expr const * arg3 = ast::deepCopy( condArg->arg3 );
 | 
|---|
| 593 |                 ast::ConditionalExpr * ret = new ast::ConditionalExpr(
 | 
|---|
| 594 |                         condArg->location, arg1, mkExpr( arg2 )->accept( *visitor ),
 | 
|---|
| 595 |                         mkExpr( arg3 )->accept( *visitor ) );
 | 
|---|
| 596 | 
 | 
|---|
| 597 |                 // Conditional expr type may not be either of the arguments,
 | 
|---|
| 598 |                 // so unify to get the result.
 | 
|---|
| 599 |                 // TODO: Maybe I could create a wrapper for this.
 | 
|---|
| 600 |                 ast::ptr<ast::Type> common = nullptr;
 | 
|---|
| 601 |                 ast::TypeEnvironment newEnv;
 | 
|---|
| 602 |                 ast::AssertionSet needAssertions, haveAssertions;
 | 
|---|
| 603 |                 ast::OpenVarSet openVars;
 | 
|---|
| 604 |                 ResolvExpr::unify( ret->arg2->result, ret->arg3->result, newEnv,
 | 
|---|
| 605 |                         needAssertions, haveAssertions, openVars, common );
 | 
|---|
| 606 |                 ret->result = common ? common : ast::deepCopy( ret->arg2->result );
 | 
|---|
| 607 |                 return ret;
 | 
|---|
| 608 |         }
 | 
|---|
| 609 |         return expr;
 | 
|---|
| 610 | }
 | 
|---|
| 611 | 
 | 
|---|
| 612 | ast::Type const * ReferenceTypeElimination::postvisit(
 | 
|---|
| 613 |                 ast::ReferenceType const * type ) {
 | 
|---|
| 614 |         return new ast::PointerType( type->base, type->qualifiers );
 | 
|---|
| 615 | }
 | 
|---|
| 616 | 
 | 
|---|
| 617 | } // namespace
 | 
|---|
| 618 | 
 | 
|---|
| 619 | // Stored elsewhere (Lvalue2, initially false):
 | 
|---|
| 620 | extern bool referencesEliminated;
 | 
|---|
| 621 | 
 | 
|---|
| 622 | void convertLvalue( ast::TranslationUnit & translationUnit ) {
 | 
|---|
| 623 |         ast::Pass<FixIntrinsicResults>::run( translationUnit );
 | 
|---|
| 624 |         ast::Pass<AddressRef>::run( translationUnit );
 | 
|---|
| 625 |         ast::Pass<ReferenceConversions>::run( translationUnit );
 | 
|---|
| 626 |         ast::Pass<FixIntrinsicArgs>::run( translationUnit );
 | 
|---|
| 627 |         ast::Pass<CollapseAddressDeref>::run( translationUnit );
 | 
|---|
| 628 |         ast::Pass<GeneralizedLvalue>::run( translationUnit );
 | 
|---|
| 629 |         // Last because other passes need reference types to work.
 | 
|---|
| 630 |         ast::Pass<ReferenceTypeElimination>::run( translationUnit );
 | 
|---|
| 631 |         // From this point forward, nothing should create reference types.
 | 
|---|
| 632 |         referencesEliminated = true;
 | 
|---|
| 633 | }
 | 
|---|
| 634 | 
 | 
|---|
| 635 | ast::Expr const * generalizedLvalue( ast::Expr const * expr ) {
 | 
|---|
| 636 |         ast::Pass<GeneralizedLvalue> visitor;
 | 
|---|
| 637 |         return expr->accept( visitor );
 | 
|---|
| 638 | }
 | 
|---|
| 639 | 
 | 
|---|
| 640 | } // namespace GenPoly
 | 
|---|
| 641 | 
 | 
|---|
| 642 | // Local Variables: //
 | 
|---|
| 643 | // tab-width: 4 //
 | 
|---|
| 644 | // mode: c++ //
 | 
|---|
| 645 | // compile-command: "make install" //
 | 
|---|
| 646 | // End: //
 | 
|---|