Author: baldrick Date: Fri Jan 25 11:36:35 2008 New Revision: 46356 URL: http://llvm.org/viewvc/llvm-project?rev=46356&view=rev Log: Fix PR1942. When returning an aggregate result, create a temporary to hold the result, and copy it out when returning.
Modified: llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp llvm-gcc-4.2/trunk/gcc/llvm-internal.h Modified: llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp?rev=46356&r1=46355&r2=46356&view=diff ============================================================================== --- llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp (original) +++ llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp Fri Jan 25 11:36:35 2008 @@ -367,6 +367,8 @@ AllocaInsertionPoint = 0; + UsedSRetBuffer = false; + ExceptionValue = 0; ExceptionSelectorValue = 0; FuncEHException = 0; @@ -411,11 +413,13 @@ LLVMBuilder Builder; std::vector<Value*> LocStack; std::vector<std::string> NameStack; + bool &UsedSRetBuffer; FunctionPrologArgumentConversion(tree FnDecl, Function::arg_iterator &ai, - const LLVMBuilder &B) - : FunctionDecl(FnDecl), AI(ai), Builder(B) {} - + const LLVMBuilder &B, + bool &SRetBuffer) + : FunctionDecl(FnDecl), AI(ai), Builder(B), UsedSRetBuffer(SRetBuffer) {} + void setName(const std::string &Name) { NameStack.push_back(Name); } @@ -435,23 +439,29 @@ // instead. assert(AI != Builder.GetInsertBlock()->getParent()->arg_end() && "No explicit return value?"); + assert(AI == Builder.GetInsertBlock()->getParent()->arg_begin() && + "Struct return is not first argument!"); AI->setName("agg.result"); - + tree ResultDecl = DECL_RESULT(FunctionDecl); tree RetTy = TREE_TYPE(TREE_TYPE(FunctionDecl)); if (TREE_CODE(RetTy) == TREE_CODE(TREE_TYPE(ResultDecl))) { - SET_DECL_LLVM(ResultDecl, AI); + // Use a buffer for the return result. This ensures that writes to the + // return value do not interfere with reads from parameters: the same + // aggregate might be used for the return value and as a parameter. + TheTreeToLLVM->EmitAutomaticVariableDecl(DECL_RESULT(FunctionDecl)); + UsedSRetBuffer = true; ++AI; return; } - + // Otherwise, this must be something returned with NRVO. assert(TREE_CODE(TREE_TYPE(ResultDecl)) == REFERENCE_TYPE && "Not type match and not passing by reference?"); // Create an alloca for the ResultDecl. Value *Tmp = TheTreeToLLVM->CreateTemporary(AI->getType()); Builder.CreateStore(AI, Tmp); - + SET_DECL_LLVM(ResultDecl, Tmp); if (TheDebugInfo) { TheDebugInfo->EmitDeclare(ResultDecl, @@ -656,7 +666,7 @@ Function::arg_iterator AI = Fn->arg_begin(); // Rename and alloca'ify real arguments. - FunctionPrologArgumentConversion Client(FnDecl, AI, Builder); + FunctionPrologArgumentConversion Client(FnDecl, AI, Builder, UsedSRetBuffer); TheLLVMABI<FunctionPrologArgumentConversion> ABIConverter(Client); // Handle the DECL_RESULT. @@ -756,6 +766,14 @@ PointerType::getUnqual(Fn->getReturnType())); RetVal = Builder.CreateLoad(RetVal, "retval"); } + } else if (UsedSRetBuffer) { + // A buffer was used for the aggregate return result. Copy it out now. + assert(Fn->arg_begin() != Fn->arg_end() && "No struct return value?"); + unsigned Alignment = expr_align(DECL_RESULT(FnDecl))/8; + bool Volatile = TREE_THIS_VOLATILE(DECL_RESULT(FnDecl)); + MemRef BufLoc(DECL_LLVM(DECL_RESULT(FnDecl)), Alignment, false); + MemRef RetLoc(Fn->arg_begin(), Alignment, Volatile); + EmitAggregateCopy(RetLoc, BufLoc, TREE_TYPE(DECL_RESULT(FnDecl))); } if (TheDebugInfo) TheDebugInfo->EmitRegionEnd(Fn, Builder.GetInsertBlock()); Builder.CreateRet(RetVal); @@ -2675,20 +2693,9 @@ // Non-bitfield aggregate value. MemRef NewLoc(LV.Ptr, Alignment, isVolatile); - if (DestLoc) { - Emit(TREE_OPERAND(exp, 1), &NewLoc); + Emit(TREE_OPERAND(exp, 1), &NewLoc); + if (DestLoc) EmitAggregateCopy(*DestLoc, NewLoc, TREE_TYPE(exp)); - } else if (TREE_CODE(TREE_OPERAND(exp, 0)) != RESULT_DECL) { - Emit(TREE_OPERAND(exp, 1), &NewLoc); - } else { - // We do this for stores into RESULT_DECL because it is possible for that - // memory area to overlap with the object being stored into it; see - // gcc.c-torture/execute/20010124-1.c. - - MemRef Tmp = CreateTempLoc(ConvertType(TREE_TYPE(TREE_OPERAND(exp,1)))); - Emit(TREE_OPERAND(exp, 1), &Tmp); - EmitAggregateCopy(NewLoc, Tmp, TREE_TYPE(TREE_OPERAND(exp,1))); - } return 0; } Modified: llvm-gcc-4.2/trunk/gcc/llvm-internal.h URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-internal.h?rev=46356&r1=46355&r2=46356&view=diff ============================================================================== --- llvm-gcc-4.2/trunk/gcc/llvm-internal.h (original) +++ llvm-gcc-4.2/trunk/gcc/llvm-internal.h Fri Jan 25 11:36:35 2008 @@ -285,7 +285,11 @@ // AllocaInsertionPoint - Place to insert alloca instructions. Lazily created // and managed by CreateTemporary. Instruction *AllocaInsertionPoint; - + + // UsedSRetBuffer - Whether a buffer was used for an aggregate return value. + // If so, it needs copying out when the function returns. + bool UsedSRetBuffer; + //===---------------------- Exception Handling --------------------------===// /// LandingPads - The landing pad for a given EH region. @@ -386,6 +390,8 @@ /// instruction's type is a pointer to the specified type. AllocaInst *CreateTemporary(const Type *Ty); + void EmitAutomaticVariableDecl(tree_node *decl); + private: // Helper functions. /// StartFunctionBody - Start the emission of 'fndecl', outputing all @@ -446,8 +452,6 @@ /// CreateTempLoc - Like CreateTemporary, but returns a MemRef. MemRef CreateTempLoc(const Type *Ty); - void EmitAutomaticVariableDecl(tree_node *decl); - /// isNoopCast - Return true if a cast from V to Ty does not change any bits. /// static bool isNoopCast(Value *V, const Type *Ty); _______________________________________________ llvm-commits mailing list llvm-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits