diff --git a/lib/Transforms/Utils/InlineFunction.cpp b/lib/Transforms/Utils/InlineFunction.cpp index 5cf0fed19f4..3f50ccdaf5a 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(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 00686341cb2..da0beab9dc7 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 +}