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