aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2010-12-20 07:45:28 +0000
committerChris Lattner <sabre@nondot.org>2010-12-20 07:45:28 +0000
commit018fb767b91d5ec396d56a3e61bd124918b59fa1 (patch)
tree404132f6b16bfc87e1ff7331587545f99a4d6a74
parent572335915f5d7306e319598803742473b0bd3525 (diff)
fix PR8769, a miscompilation by inliner when inlining a function with a byval
argument. The generated alloca has to have at least the alignment of the byval, if not, the client may be making assumptions that the new alloca won't satisfy. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@122234 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Transforms/Utils/InlineFunction.cpp16
-rw-r--r--test/Transforms/Inline/byval.ll24
2 files changed, 34 insertions, 6 deletions
diff --git a/lib/Transforms/Utils/InlineFunction.cpp b/lib/Transforms/Utils/InlineFunction.cpp
index 5cf0fed19f..3f50ccdaf5 100644
--- a/lib/Transforms/Utils/InlineFunction.cpp
+++ b/lib/Transforms/Utils/InlineFunction.cpp
@@ -252,7 +252,6 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI) {
CalledFunc->isDeclaration() || // call, or call to a vararg function!
CalledFunc->getFunctionType()->isVarArg()) return false;
-
// If the call to the callee is not a tail call, we must clear the 'tail'
// flags on any calls that we inline.
bool MustClearTailCallFlags =
@@ -308,14 +307,19 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI) {
if (CalledFunc->paramHasAttr(ArgNo+1, Attribute::ByVal) &&
!CalledFunc->onlyReadsMemory()) {
const Type *AggTy = cast<PointerType>(I->getType())->getElementType();
- const Type *VoidPtrTy =
- Type::getInt8PtrTy(Context);
+ const Type *VoidPtrTy = Type::getInt8PtrTy(Context);
// Create the alloca. If we have TargetData, use nice alignment.
unsigned Align = 1;
- if (IFI.TD) Align = IFI.TD->getPrefTypeAlignment(AggTy);
- Value *NewAlloca = new AllocaInst(AggTy, 0, Align,
- I->getName(),
+ if (IFI.TD)
+ Align = IFI.TD->getPrefTypeAlignment(AggTy);
+
+ // If the byval had an alignment specified, we *must* use at least that
+ // alignment, as it is required by the byval argument (and uses of the
+ // pointer inside the callee).
+ Align = std::max(Align, CalledFunc->getParamAlignment(ArgNo+1));
+
+ Value *NewAlloca = new AllocaInst(AggTy, 0, Align, I->getName(),
&*Caller->begin()->begin());
// Emit a memcpy.
const Type *Tys[3] = {VoidPtrTy, VoidPtrTy, Type::getInt64Ty(Context)};
diff --git a/test/Transforms/Inline/byval.ll b/test/Transforms/Inline/byval.ll
index 00686341cb..da0beab9dc 100644
--- a/test/Transforms/Inline/byval.ll
+++ b/test/Transforms/Inline/byval.ll
@@ -56,3 +56,27 @@ entry:
; CHECK-NOT: call void @llvm.memcpy
; CHECK: ret i32
}
+
+
+; Inlining a byval with an explicit alignment needs to use *at least* that
+; alignment on the generated alloca.
+; PR8769
+declare void @g3(%struct.ss* %p)
+
+define internal void @f3(%struct.ss* byval align 64 %b) nounwind {
+ call void @g3(%struct.ss* %b) ;; Could make alignment assumptions!
+ ret void
+}
+
+define void @test3() nounwind {
+entry:
+ %S = alloca %struct.ss, align 1 ;; May not be aligned.
+ call void @f3( %struct.ss* byval align 64 %S) nounwind
+ ret void
+; CHECK: @test3()
+; CHECK: %b = alloca %struct.ss, align 64
+; CHECK: %S = alloca %struct.ss
+; CHECK: call void @llvm.memcpy
+; CHECK: call void @g3(%struct.ss* %b)
+; CHECK: ret void
+}