[llvm-commits] [llvm-gcc-4.0] r46359 - in /llvm-gcc-4.0/trunk/gcc: llvm-convert.cpp llvm-internal.h
Duncan Sands
baldrick at free.fr
Fri Jan 25 09:45:31 PST 2008
Author: baldrick
Date: Fri Jan 25 11:45:31 2008
New Revision: 46359
URL: http://llvm.org/viewvc/llvm-project?rev=46359&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.0/trunk/gcc/llvm-convert.cpp
llvm-gcc-4.0/trunk/gcc/llvm-internal.h
Modified: llvm-gcc-4.0/trunk/gcc/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.0/trunk/gcc/llvm-convert.cpp?rev=46359&r1=46358&r2=46359&view=diff
==============================================================================
--- llvm-gcc-4.0/trunk/gcc/llvm-convert.cpp (original)
+++ llvm-gcc-4.0/trunk/gcc/llvm-convert.cpp Fri Jan 25 11:45:31 2008
@@ -351,7 +351,9 @@
}
AllocaInsertionPoint = 0;
-
+
+ UsedSRetBuffer = false;
+
CleanupFilter = NULL_TREE;
ExceptionValue = 0;
ExceptionSelectorValue = 0;
@@ -384,11 +386,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);
}
@@ -408,23 +412,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,
@@ -629,7 +639,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.
@@ -729,6 +739,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);
@@ -3137,20 +3155,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.0/trunk/gcc/llvm-internal.h
URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.0/trunk/gcc/llvm-internal.h?rev=46359&r1=46358&r2=46359&view=diff
==============================================================================
--- llvm-gcc-4.0/trunk/gcc/llvm-internal.h (original)
+++ llvm-gcc-4.0/trunk/gcc/llvm-internal.h Fri Jan 25 11:45:31 2008
@@ -260,7 +260,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 / Finally Block Handling ------------------===//
struct BranchFixup {
@@ -446,7 +450,9 @@
/// inserting it into the entry block and returning it. The resulting
/// instruction's type is a pointer to the specified type.
AllocaInst *CreateTemporary(const Type *Ty);
-
+
+ void EmitAutomaticVariableDecl(tree_node *decl);
+
private: // Helper functions.
/// EmitBlock - Add the specified basic block to the end of the function. If
@@ -481,8 +487,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);
More information about the llvm-commits
mailing list