diff --git a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp --- a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp +++ b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp @@ -764,6 +764,15 @@ if (CB->isMustTailCall()) return nullptr; + // If the caller is marked minsize, this transformation may increase code + // size. We assume that there is more than one call to this function since + // otherwise this function would be inlined or is dead. + // TODO: compare the number of loads/stores removed from the function with + // the number of introduced loads in callees to see if this is profitable + // code-size-wise. + if (CB->getFunction()->hasMinSize()) + return nullptr; + if (CB->getFunction() == F) IsRecursive = true; } diff --git a/llvm/test/Transforms/ArgumentPromotion/minsize.ll b/llvm/test/Transforms/ArgumentPromotion/minsize.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/ArgumentPromotion/minsize.ll @@ -0,0 +1,63 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2 +; RUN: opt -passes=argpromotion -S < %s | FileCheck %s + +define internal i32 @f1(ptr %p) { +; CHECK-LABEL: define internal i32 @f1 +; CHECK-SAME: (i32 [[P_0_VAL:%.*]]) { +; CHECK-NEXT: ret i32 [[P_0_VAL]] +; + %i = load i32, ptr %p + ret i32 %i +} + +define i32 @g1(ptr %p) { +; CHECK-LABEL: define i32 @g1 +; CHECK-SAME: (ptr [[P:%.*]]) { +; CHECK-NEXT: [[P_VAL:%.*]] = load i32, ptr [[P]], align 4 +; CHECK-NEXT: [[I:%.*]] = call i32 @f1(i32 [[P_VAL]]) +; CHECK-NEXT: ret i32 [[I]] +; + %i = call i32 @f1(ptr %p) + ret i32 %i +} + +define i32 @g2(ptr %p) { +; CHECK-LABEL: define i32 @g2 +; CHECK-SAME: (ptr [[P:%.*]]) { +; CHECK-NEXT: [[P_VAL:%.*]] = load i32, ptr [[P]], align 4 +; CHECK-NEXT: [[I:%.*]] = call i32 @f1(i32 [[P_VAL]]) +; CHECK-NEXT: ret i32 [[I]] +; + %i = call i32 @f1(ptr %p) + ret i32 %i +} + +define internal i32 @f2(ptr %p) { +; CHECK-LABEL: define internal i32 @f2 +; CHECK-SAME: (ptr [[P:%.*]]) { +; CHECK-NEXT: [[I:%.*]] = load i32, ptr [[P]], align 4 +; CHECK-NEXT: ret i32 [[I]] +; + %i = load i32, ptr %p + ret i32 %i +} + +define i32 @h1(ptr %p) minsize { +; CHECK-LABEL: define i32 @h1 +; CHECK-SAME: (ptr [[P:%.*]]) #[[ATTR0:[0-9]+]] { +; CHECK-NEXT: [[I:%.*]] = call i32 @f2(ptr [[P]]) +; CHECK-NEXT: ret i32 [[I]] +; + %i = call i32 @f2(ptr %p) + ret i32 %i +} + +define i32 @h2(ptr %p) { +; CHECK-LABEL: define i32 @h2 +; CHECK-SAME: (ptr [[P:%.*]]) { +; CHECK-NEXT: [[I:%.*]] = call i32 @f2(ptr [[P]]) +; CHECK-NEXT: ret i32 [[I]] +; + %i = call i32 @f2(ptr %p) + ret i32 %i +}