Changeset cce9429
- Timestamp:
- Dec 13, 2016, 6:42:39 PM (8 years ago)
- Branches:
- ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
- Children:
- 1aa4b71
- Parents:
- 31f379c
- Location:
- src
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
src/GenPoly/Box.cc
r31f379c rcce9429 131 131 ScopedMap< std::string, DeclarationWithType* > adapters; ///< Set of adapter functions in the current scope 132 132 133 std::map< ApplicationExpr *, Expression * > retVals; 134 133 135 DeclarationWithType *retval; 134 bool useRetval;135 136 UniqueName tempNamer; 136 137 }; … … 497 498 } 498 499 499 Pass1::Pass1() : useRetval( false ),tempNamer( "_temp" ) {}500 Pass1::Pass1() : tempNamer( "_temp" ) {} 500 501 501 502 /// Returns T if the given declaration is a function with parameter (T*) for some TypeInstType T, NULL otherwise … … 667 668 668 669 DeclarationWithType *oldRetval = retval; 669 bool oldUseRetval = useRetval;670 670 671 671 // process polymorphic return value 672 retval = 0;673 if ( isDynRet( functionDecl->get_functionType() ) && functionDecl->get_linkage() == LinkageSpec::Cforall) {672 retval = nullptr; 673 if ( isDynRet( functionDecl->get_functionType() ) && functionDecl->get_linkage() != LinkageSpec::C ) { 674 674 retval = functionDecl->get_functionType()->get_returnVals().front(); 675 675 … … 700 700 if ( adapters.find( mangleName ) == adapters.end() ) { 701 701 std::string adapterName = makeAdapterName( mangleName ); 702 adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, new ObjectDecl( adapterName, DeclarationNode::NoStorageClass, LinkageSpec::C, 0, new PointerType( Type::Qualifiers(), makeAdapterType( *funType, scopeTyVars ) ), 0) ) );702 adapters.insert( std::pair< std::string, DeclarationWithType *>( mangleName, new ObjectDecl( adapterName, DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, new PointerType( Type::Qualifiers(), makeAdapterType( *funType, scopeTyVars ) ), nullptr ) ) ); 703 703 } // if 704 704 } // for … … 712 712 dtorOps.endScope(); 713 713 retval = oldRetval; 714 useRetval = oldUseRetval;715 714 doEndScope(); 716 715 } // if … … 724 723 725 724 Expression *Pass1::mutate( CommaExpr *commaExpr ) { 726 bool oldUseRetval = useRetval; 727 useRetval = false; 725 // Attempting to find application expressions that were mutated by the copy constructor passes 726 // to use an explicit return variable, so that the variable can be reused as a parameter to the 727 // call rather than creating a new temp variable. Previously this step was an optimization, but 728 // with the introduction of tuples and UniqueExprs, it is necessary to ensure that they use the same variable. 729 // Essentially, looking for pattern: (x=f(...), x) 730 // To compound the issue, the right side can be *x, etc. because of lvalue-returning functions 731 if ( UntypedExpr * assign = dynamic_cast< UntypedExpr * >( commaExpr->get_arg1() ) ) { 732 if ( InitTweak::isAssignment( InitTweak::getFunctionName( assign ) ) ) { 733 assert( assign->get_args().size() == 2 ); 734 if ( ApplicationExpr * appExpr = dynamic_cast< ApplicationExpr * > ( assign->get_args().back() ) ) { 735 // first argument is assignable, so it must be an lvalue, so it should be legal to take its address. 736 retVals[appExpr] = assign->get_args().front(); 737 } 738 } 739 } 740 728 741 commaExpr->set_arg1( maybeMutate( commaExpr->get_arg1(), *this ) ); 729 useRetval = oldUseRetval;730 742 commaExpr->set_arg2( maybeMutate( commaExpr->get_arg2(), *this ) ); 731 743 return commaExpr; … … 733 745 734 746 Expression *Pass1::mutate( ConditionalExpr *condExpr ) { 735 bool oldUseRetval = useRetval;736 useRetval = false;737 747 condExpr->set_arg1( maybeMutate( condExpr->get_arg1(), *this ) ); 738 useRetval = oldUseRetval;739 748 condExpr->set_arg2( maybeMutate( condExpr->get_arg2(), *this ) ); 740 749 condExpr->set_arg3( maybeMutate( condExpr->get_arg3(), *this ) ); … … 783 792 } else { 784 793 // xxx - should this be an assertion? 785 throw SemanticError( "unbound type variable: " + tyParm->first + " in application ", appExpr ); 794 std::string x = env ? toString( *env ) : "missing env"; 795 throw SemanticError( x + "\n" + "unbound type variable: " + tyParm->first + " in application ", appExpr ); 786 796 } // if 787 797 } // if … … 819 829 Expression *Pass1::addRetParam( ApplicationExpr *appExpr, FunctionType *function, Type *retType, std::list< Expression *>::iterator &arg ) { 820 830 // Create temporary to hold return value of polymorphic function and produce that temporary as a result 821 // using a comma expression. Possibly change comma expression into statement expression "{}" for multiple 822 // return values. 831 // using a comma expression. 823 832 assert( retType ); 824 ObjectDecl *newObj = makeTemporary( retType->clone() ); 825 Expression *paramExpr = new VariableExpr( newObj ); 833 834 Expression * paramExpr = nullptr; 835 // try to use existing return value parameter if it exists, otherwise create a new temporary 836 if ( retVals.count( appExpr ) ) { 837 paramExpr = retVals[appExpr]->clone(); 838 } else { 839 ObjectDecl *newObj = makeTemporary( retType->clone() ); 840 paramExpr = new VariableExpr( newObj ); 841 } 842 Expression * retExpr = paramExpr->clone(); 826 843 827 844 // If the type of the temporary is not polymorphic, box temporary by taking its address; 828 845 // otherwise the temporary is already boxed and can be used directly. 829 if ( ! isPolyType( newObj->get_type(), scopeTyVars, env ) ) {846 if ( ! isPolyType( paramExpr->get_result(), scopeTyVars, env ) ) { 830 847 paramExpr = new AddressExpr( paramExpr ); 831 848 } // if … … 833 850 arg++; 834 851 // Build a comma expression to call the function and emulate a normal return. 835 CommaExpr *commaExpr = new CommaExpr( appExpr, new VariableExpr( newObj ));852 CommaExpr *commaExpr = new CommaExpr( appExpr, retExpr ); 836 853 commaExpr->set_env( appExpr->get_env() ); 837 854 appExpr->set_env( 0 ); … … 851 868 Type *concrete = env->lookup( typeInst->get_name() ); 852 869 if ( concrete == 0 ) { 853 throw SemanticError( "Unbound type variable " + typeInst->get_name() + " in ", appExpr ); 870 // xxx - should this be an assertion? 871 std::string x = env ? toString( *env ) : "missing env"; 872 throw SemanticError( x + "\n" + "Unbound type variable " + typeInst->get_name() + " in ", appExpr ); 854 873 } // if 855 874 return concrete; … … 1259 1278 // } 1260 1279 // std::cerr << "\n"; 1261 bool oldUseRetval = useRetval;1262 useRetval = false;1263 1280 appExpr->get_function()->acceptMutator( *this ); 1264 1281 mutateAll( appExpr->get_args(), *this ); 1265 useRetval = oldUseRetval;1266 1282 1267 1283 assert( appExpr->get_function()->has_result() ); … … 1545 1561 } 1546 1562 1563 /// determines if `pref` is a prefix of `str` 1564 bool isPrefix( const std::string & str, const std::string & pref ) { 1565 if ( pref.size() > str.size() ) return false; 1566 auto its = std::mismatch( pref.begin(), pref.end(), str.begin() ); 1567 return its.first == pref.end(); 1568 } 1569 1547 1570 DeclarationWithType * Pass2::mutate( FunctionDecl *functionDecl ) { 1548 return handleDecl( functionDecl, functionDecl->get_functionType() ); 1571 if ( ! LinkageSpec::isBuiltin( functionDecl->get_linkage() ) ) { 1572 // std::cerr << "mutating function: " << functionDecl->get_name() << std::endl; 1573 } 1574 functionDecl = safe_dynamic_cast< FunctionDecl * > ( handleDecl( functionDecl, functionDecl->get_functionType() ) ); 1575 FunctionType * ftype = functionDecl->get_functionType(); 1576 if ( ! ftype->get_returnVals().empty() && functionDecl->get_statements() ) { 1577 if ( functionDecl->get_name() != "?=?" && ! isPrefix( functionDecl->get_name(), "_thunk" ) ) { // xxx - remove check for ?=? once reference types are in; remove check for prefix once thunks properly use ctor/dtors 1578 assert( ftype->get_returnVals().size() == 1 ); 1579 DeclarationWithType * retval = ftype->get_returnVals().front(); 1580 if ( retval->get_name() == "" ) { 1581 retval->set_name( "_retval" ); 1582 } 1583 functionDecl->get_statements()->get_kids().push_front( new DeclStmt( noLabels, retval ) ); 1584 DeclarationWithType * newRet = retval->clone(); // for ownership purposes 1585 ftype->get_returnVals().front() = newRet; 1586 } 1587 } 1588 return functionDecl; 1549 1589 } 1550 1590 -
src/InitTweak/GenInit.cc
r31f379c rcce9429 46 46 ReturnFixer(); 47 47 48 using GenPoly::PolyMutator::mutate; 48 typedef GenPoly::PolyMutator Parent; 49 using Parent::mutate; 49 50 virtual DeclarationWithType * mutate( FunctionDecl *functionDecl ) override; 50 51 virtual Statement * mutate( ReturnStmt * returnStmt ) override; … … 142 143 // hands off if the function returns an lvalue - we don't want to allocate a temporary if a variable's address 143 144 // is being returned 145 // Note: under the assumption that assignments return *this, checking for ?=? here is an optimization, since it shouldn't be necessary to copy construct `this`. This is a temporary optimization until reference types are added, at which point this should be removed, along with the analogous optimization in copy constructor generation. 144 146 if ( returnStmt->get_expr() && returnVals.size() == 1 && funcName != "?=?" && ! returnVals.front()->get_type()->get_isLvalue() ) { 145 // ensure return value is not destructed by explicitly creating 146 // an empty SingleInit node wherein maybeConstruct is false 147 ObjectDecl *newObj = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, returnVals.front()->get_type()->clone(), new ListInit( std::list<Initializer*>(), noDesignators, false ) ); 148 stmtsToAdd.push_back( new DeclStmt( noLabels, newObj ) ); 149 150 // and explicitly create the constructor expression separately 147 // explicitly construct the return value using the return expression and the retVal object 148 assertf( returnVals.front()->get_name() != "", "Function %s has unnamed return value\n", funcName.c_str() ); 151 149 UntypedExpr *construct = new UntypedExpr( new NameExpr( "?{}" ) ); 152 construct->get_args().push_back( new AddressExpr( new VariableExpr( newObj) ) );150 construct->get_args().push_back( new AddressExpr( new VariableExpr( returnVals.front() ) ) ); 153 151 construct->get_args().push_back( returnStmt->get_expr() ); 154 152 stmtsToAdd.push_back(new ExprStmt(noLabels, construct)); 155 153 156 returnStmt->set_expr( new VariableExpr( newObj ) ); 154 // return the retVal object 155 returnStmt->set_expr( new VariableExpr( returnVals.front() ) ); 157 156 } // if 158 157 return returnStmt; … … 160 159 161 160 DeclarationWithType* ReturnFixer::mutate( FunctionDecl *functionDecl ) { 162 // xxx - need to handle named return values - this pass may need to happen163 // after resolution? the ordering is tricky because return statements must be164 // constructed - the simplest way to do that (while also handling multiple165 // returns) is to structure the returnVals into a tuple, as done here.166 // however, if the tuple return value is structured before resolution,167 // it's difficult to resolve named return values, since the name is lost168 // in conversion to a tuple. this might be easiest to deal with169 // after reference types are added, as it may then be possible to170 // uniformly move named return values to the parameter list directly171 161 ValueGuard< FunctionType * > oldFtype( ftype ); 172 162 ValueGuard< std::string > oldFuncName( funcName ); 173 163 174 164 ftype = functionDecl->get_functionType(); 175 std::list< DeclarationWithType * > & retVals = ftype->get_returnVals();176 if ( retVals.size() > 1 ) {177 TupleType * tupleType = safe_dynamic_cast< TupleType * >( ResolvExpr::extractResultType( ftype ) );178 ObjectDecl * newRet = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, tupleType, new ListInit( std::list<Initializer*>(), noDesignators, false ) );179 retVals.clear();180 retVals.push_back( newRet );181 }182 165 funcName = functionDecl->get_name(); 183 DeclarationWithType * decl = Mutator::mutate( functionDecl ); 184 return decl; 166 return Parent::mutate( functionDecl ); 185 167 } 186 168 -
src/SymTab/Validate.cc
r31f379c rcce9429 86 86 }; 87 87 88 /// Fix return types so that every function returns exactly one value 89 class ReturnTypeFixer : public Visitor { 90 public: 91 static void fix( std::list< Declaration * > &translationUnit ); 92 93 virtual void visit( FunctionType * ftype ); 94 }; 95 88 96 /// Replaces enum types by int, and function or array types in function parameter and return lists by appropriate pointers. 89 97 class EnumAndPointerDecayPass : public Visitor { … … 94 102 95 103 /// Associates forward declarations of aggregates with their definitions 96 class Pass2final : public Indexer {104 class LinkReferenceToTypes final : public Indexer { 97 105 typedef Indexer Parent; 98 106 public: 99 Pass2( bool doDebug, const Indexer *indexer );107 LinkReferenceToTypes( bool doDebug, const Indexer *indexer ); 100 108 private: 101 109 using Indexer::visit; … … 193 201 void validate( std::list< Declaration * > &translationUnit, bool doDebug ) { 194 202 EnumAndPointerDecayPass epc; 195 Pass2 pass2( doDebug, 0 );203 LinkReferenceToTypes lrt( doDebug, 0 ); 196 204 Pass3 pass3( 0 ); 197 205 CompoundLiteral compoundliteral; … … 199 207 EliminateTypedef::eliminateTypedef( translationUnit ); 200 208 HoistStruct::hoistStruct( translationUnit ); 209 ReturnTypeFixer::fix( translationUnit ); // must happen before autogen 201 210 autogenerateRoutines( translationUnit ); // moved up, used to be below compoundLiteral - currently needs EnumAndPointerDecayPass 202 211 acceptAll( translationUnit, epc ); 203 acceptAll( translationUnit, pass2);212 acceptAll( translationUnit, lrt ); 204 213 ReturnChecker::checkFunctionReturns( translationUnit ); 205 214 compoundliteral.mutateDeclarationList( translationUnit ); … … 210 219 void validateType( Type *type, const Indexer *indexer ) { 211 220 EnumAndPointerDecayPass epc; 212 Pass2 pass2( false, indexer );221 LinkReferenceToTypes lrt( false, indexer ); 213 222 Pass3 pass3( indexer ); 214 223 type->accept( epc ); 215 type->accept( pass2);224 type->accept( lrt ); 216 225 type->accept( pass3 ); 217 226 } … … 324 333 } 325 334 326 Pass2::Pass2( bool doDebug, const Indexer *other_indexer ) : Indexer( doDebug ) {335 LinkReferenceToTypes::LinkReferenceToTypes( bool doDebug, const Indexer *other_indexer ) : Indexer( doDebug ) { 327 336 if ( other_indexer ) { 328 337 indexer = other_indexer; … … 332 341 } 333 342 334 void Pass2::visit( StructInstType *structInst ) {343 void LinkReferenceToTypes::visit( StructInstType *structInst ) { 335 344 Parent::visit( structInst ); 336 345 StructDecl *st = indexer->lookupStruct( structInst->get_name() ); … … 346 355 } 347 356 348 void Pass2::visit( UnionInstType *unionInst ) {357 void LinkReferenceToTypes::visit( UnionInstType *unionInst ) { 349 358 Parent::visit( unionInst ); 350 359 UnionDecl *un = indexer->lookupUnion( unionInst->get_name() ); … … 359 368 } 360 369 361 void Pass2::visit( TraitInstType *contextInst ) {370 void LinkReferenceToTypes::visit( TraitInstType *contextInst ) { 362 371 Parent::visit( contextInst ); 363 372 if ( contextInst->get_name() == "sized" ) { … … 398 407 } 399 408 400 void Pass2::visit( StructDecl *structDecl ) {409 void LinkReferenceToTypes::visit( StructDecl *structDecl ) { 401 410 // visit struct members first so that the types of self-referencing members are updated properly 402 411 Parent::visit( structDecl ); … … 412 421 } 413 422 414 void Pass2::visit( UnionDecl *unionDecl ) {423 void LinkReferenceToTypes::visit( UnionDecl *unionDecl ) { 415 424 Parent::visit( unionDecl ); 416 425 if ( ! unionDecl->get_members().empty() ) { … … 425 434 } 426 435 427 void Pass2::visit( TypeInstType *typeInst ) {436 void LinkReferenceToTypes::visit( TypeInstType *typeInst ) { 428 437 if ( NamedTypeDecl *namedTypeDecl = lookupType( typeInst->get_name() ) ) { 429 438 if ( TypeDecl *typeDecl = dynamic_cast< TypeDecl * >( namedTypeDecl ) ) { … … 747 756 return new VariableExpr( newtempvar ); 748 757 } 758 759 void ReturnTypeFixer::fix( std::list< Declaration * > &translationUnit ) { 760 ReturnTypeFixer fixer; 761 acceptAll( translationUnit, fixer ); 762 } 763 764 void ReturnTypeFixer::visit( FunctionType * ftype ) { 765 static UniqueName tempNamer( "_retval" ); 766 767 // xxx - need to handle named return values - this information needs to be saved somehow 768 // so that resolution has access to the names. 769 // Note that this pass needs to happen early so that other passes which look for tuple types 770 // find them in all of the right places, including function return types. 771 std::list< DeclarationWithType * > & retVals = ftype->get_returnVals(); 772 if ( retVals.size() > 1 ) { 773 // generate a single return parameter which is the tuple of all of the return values 774 TupleType * tupleType = safe_dynamic_cast< TupleType * >( ResolvExpr::extractResultType( ftype ) ); 775 // ensure return value is not destructed by explicitly creating an empty ListInit node wherein maybeConstruct is false. 776 ObjectDecl * newRet = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, tupleType, new ListInit( std::list<Initializer*>(), noDesignators, false ) ); 777 deleteAll( retVals ); 778 retVals.clear(); 779 retVals.push_back( newRet ); 780 } else if ( retVals.size() == 1 ) { 781 // ensure other return values have a name 782 DeclarationWithType * ret = retVals.front(); 783 if ( ret->get_name() == "" ) { 784 ret->set_name( tempNamer.newName() ); 785 } 786 } 787 } 749 788 } // namespace SymTab 750 789
Note: See TracChangeset
for help on using the changeset viewer.