From af9b325d232f52ca858c67cd497b79f5e63716af Mon Sep 17 00:00:00 2001 From: Eli Friedman Date: Tue, 17 May 2011 21:08:01 +0000 Subject: [PATCH] For calls returning first-class aggregates, store by element instead of creating aggregate stores in common cases. This is more friendly to fast-isel. llvm-svn: 131490 --- clang/lib/CodeGen/CGCall.cpp | 27 +++++++++++++++++-- .../property-object-conditional-exp.mm | 7 ++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 6b6f3176b029..fba89a76fc65 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -513,6 +513,29 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, return CGF.Builder.CreateLoad(Tmp); } +// Function to store a first-class aggregate into memory. We prefer to +// store the elements rather than the aggregate to be more friendly to +// fast-isel. +// FIXME: Do we need to recurse here? +static void BuildAggStore(CodeGenFunction &CGF, llvm::Value *Val, + llvm::Value *DestPtr, bool DestIsVolatile, + bool LowAlignment) { + // Prefer scalar stores to first-class aggregate stores. + if (const llvm::StructType *STy = + dyn_cast(Val->getType())) { + for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { + llvm::Value *EltPtr = CGF.Builder.CreateConstGEP2_32(DestPtr, 0, i); + llvm::Value *Elt = CGF.Builder.CreateExtractValue(Val, i); + llvm::StoreInst *SI = CGF.Builder.CreateStore(Elt, EltPtr, + DestIsVolatile); + if (LowAlignment) + SI->setAlignment(1); + } + } else { + CGF.Builder.CreateStore(Val, DestPtr, DestIsVolatile); + } +} + /// CreateCoercedStore - Create a store to \arg DstPtr from \arg Src, /// where the source and destination may have different types. /// @@ -553,7 +576,7 @@ static void CreateCoercedStore(llvm::Value *Src, llvm::Value *Casted = CGF.Builder.CreateBitCast(DstPtr, llvm::PointerType::getUnqual(SrcTy)); // FIXME: Use better alignment / avoid requiring aligned store. - CGF.Builder.CreateStore(Src, Casted, DstIsVolatile)->setAlignment(1); + BuildAggStore(CGF, Src, Casted, DstIsVolatile, true); } else { // Otherwise do coercion through memory. This is stupid, but // simple. @@ -1409,7 +1432,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, DestPtr = CreateMemTemp(RetTy, "agg.tmp"); DestIsVolatile = false; } - Builder.CreateStore(CI, DestPtr, DestIsVolatile); + BuildAggStore(*this, CI, DestPtr, DestIsVolatile, false); return RValue::getAggregate(DestPtr); } return RValue::get(CI); diff --git a/clang/test/CodeGenObjCXX/property-object-conditional-exp.mm b/clang/test/CodeGenObjCXX/property-object-conditional-exp.mm index 826c351e79ef..a3c1027ed709 100644 --- a/clang/test/CodeGenObjCXX/property-object-conditional-exp.mm +++ b/clang/test/CodeGenObjCXX/property-object-conditional-exp.mm @@ -23,7 +23,12 @@ extern "C" bool CGRectIsEmpty(CGRect); CGRect virtualBounds; // CHECK: [[SRC:%.*]] = call %struct.CGRect bitcast (i8* (i8*, i8*, ...)* @objc_msgSend -// CHECK-NEXT:store %struct.CGRect [[SRC]], %struct.CGRect* +// CHECK-NEXT:getelementptr %struct.CGRect* [[SRC:%.*]] +// CHECK-NEXT:extractvalue +// CHECK-NEXT:store +// CHECK-NEXT:getelementptr %struct.CGRect* [[SRC:%.*]] +// CHECK-NEXT:extractvalue +// CHECK-NEXT:store dataRect = CGRectIsEmpty(virtualBounds) ? self.bounds : virtualBounds; dataRect = CGRectIsEmpty(virtualBounds) ? [self bounds] : virtualBounds; dataRect = CGRectIsEmpty(virtualBounds) ? virtualBounds : self.bounds;