diff --git a/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp b/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp --- a/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp +++ b/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp @@ -424,6 +424,21 @@ *FailureReason = "Argument type mismatch"; return false; } + // Make sure that the callee and call agree on byval/inalloca. The types do + // not have to match. + + if (Callee->hasParamAttribute(I, Attribute::ByVal) != + CB.getAttributes().hasParamAttr(I, Attribute::ByVal)) { + if (FailureReason) + *FailureReason = "byval mismatch"; + return false; + } + if (Callee->hasParamAttribute(I, Attribute::InAlloca) != + CB.getAttributes().hasParamAttr(I, Attribute::InAlloca)) { + if (FailureReason) + *FailureReason = "inalloca mismatch"; + return false; + } } for (; I < NumArgs; I++) { // Vararg functions can have more arguments than parameters. @@ -488,10 +503,11 @@ AttrBuilder ArgAttrs(CallerPAL.getParamAttrs(ArgNo)); ArgAttrs.remove(AttributeFuncs::typeIncompatible(FormalTy)); - // If byval is used, this must be a pointer type, and the byval type must - // match the element type. Update it if present. + // We may have a different byval/inalloca type. if (ArgAttrs.getByValType()) ArgAttrs.addByValAttr(Callee->getParamByValType(ArgNo)); + if (ArgAttrs.getInAllocaType()) + ArgAttrs.addInAllocaAttr(Callee->getParamInAllocaType(ArgNo)); NewArgAttrs.push_back(AttributeSet::get(Ctx, ArgAttrs)); AttributeChanged = true; diff --git a/llvm/test/Transforms/PGOProfile/mismatched-byval.ll b/llvm/test/Transforms/PGOProfile/mismatched-byval.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/PGOProfile/mismatched-byval.ll @@ -0,0 +1,22 @@ +; RUN: opt -passes=pgo-icall-prom -profile-summary-hot-count=10 -S < %s -pass-remarks-output=- | FileCheck %s + +; CHECK: byval mismatch + +define void @a(i8* %0) !prof !0 { + ret void +} + +define void @b(void (i64*)** %v, i64* %p) !prof !1 { +; CHECK-LABEL: @b +; CHECK-NEXT: load +; CHECK-NEXT: call void {{.*}}(i64* byval(i64) +; CHECK-NEXT: ret void +; + %a = load void (i64*)*, void (i64*)** %v + call void %a(i64* byval(i64) %p), !prof !2 + ret void +} + +!0 = !{!"function_entry_count", i64 36} +!1 = !{!"function_entry_count", i64 1} +!2 = !{!"VP", i32 0, i64 18, i64 12157170054180749580, i64 18} diff --git a/llvm/test/Transforms/PGOProfile/mismatched-inalloca.ll b/llvm/test/Transforms/PGOProfile/mismatched-inalloca.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/PGOProfile/mismatched-inalloca.ll @@ -0,0 +1,21 @@ +; RUN: opt -passes=pgo-icall-prom -profile-summary-hot-count=10 -S < %s -pass-remarks-output=- | FileCheck %s + +; CHECK: inalloca mismatch + +define void @a(i8* %0) !prof !0 { + ret void +} + +define void @b(void (i64*)** %v, i64* %p) !prof !1 { +; CHECK-LABEL: @b +; CHECK-NEXT: load +; CHECK-NEXT: call void {{.*}}(i64* inalloca(i64) +; CHECK-NEXT: ret void + %a = load void (i64*)*, void (i64*)** %v + call void %a(i64* inalloca(i64) %p), !prof !2 + ret void +} + +!0 = !{!"function_entry_count", i64 36} +!1 = !{!"function_entry_count", i64 1} +!2 = !{!"VP", i32 0, i64 18, i64 12157170054180749580, i64 18}