[llvm] 098afdb - [ArgPromotion] Make a non-byval promotion attempt first
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Thu May 12 07:45:03 PDT 2022
Author: Pavel Samolysov
Date: 2022-05-12T16:44:52+02:00
New Revision: 098afdb0a0f9254f84733fb1987018528a89accc
URL: https://github.com/llvm/llvm-project/commit/098afdb0a0f9254f84733fb1987018528a89accc
DIFF: https://github.com/llvm/llvm-project/commit/098afdb0a0f9254f84733fb1987018528a89accc.diff
LOG: [ArgPromotion] Make a non-byval promotion attempt first
It makes sense to make a non-byval promotion attempt first and then
fall back to the byval one. The non-byval ('usual') promotion is
generally better, for example it does promotion even when a structure
has more elements than 'MaxElements' but not all of them are actually
used in the function.
Differential Revision: https://reviews.llvm.org/D124514
Added:
llvm/test/Transforms/ArgumentPromotion/byval-through-pointer-promotion.ll
Modified:
llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
llvm/test/Transforms/ArgumentPromotion/dbg.ll
llvm/test/Transforms/ArgumentPromotion/fp80.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
index a33cb0bd113a3..bf769ec62c30b 100644
--- a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
+++ b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp
@@ -730,7 +730,7 @@ static bool canPaddingBeAccessed(Argument *Arg) {
Value *V = WorkList.pop_back_val();
if (isa<GetElementPtrInst>(V) || isa<PHINode>(V)) {
if (PtrValues.insert(V).second)
- llvm::append_range(WorkList, V->users());
+ append_range(WorkList, V->users());
} else if (StoreInst *Store = dyn_cast<StoreInst>(V)) {
Stores.push_back(Store);
} else if (!isa<LoadInst>(V)) {
@@ -848,9 +848,23 @@ promoteArguments(Function *F, function_ref<AAResults &(Function &F)> AARGetter,
}
}
- // If this is a byval argument, and if the aggregate type is small, just
- // pass the elements, which is always safe, if the passed value is densely
- // packed or if we can prove the padding bytes are never accessed.
+ // If we can promote the pointer to its value.
+ SmallVector<OffsetAndArgPart, 4> ArgParts;
+ if (findArgParts(PtrArg, DL, AAR, MaxElements, IsRecursive, ArgParts)) {
+ SmallVector<Type *, 4> Types;
+ for (const auto &Pair : ArgParts)
+ Types.push_back(Pair.second.Ty);
+
+ if (areTypesABICompatible(Types, *F, TTI)) {
+ ArgsToPromote.insert({PtrArg, std::move(ArgParts)});
+ continue;
+ }
+ }
+
+ // Otherwise, if this is a byval argument, and if the aggregate type is
+ // small, just pass the elements, which is always safe, if the passed value
+ // is densely packed or if we can prove the padding bytes are never
+ // accessed.
//
// Only handle arguments with specified alignment; if it's unspecified, the
// actual alignment of the argument is target-specific.
@@ -859,43 +873,32 @@ promoteArguments(Function *F, function_ref<AAResults &(Function &F)> AARGetter,
ByValTy && PtrArg->getParamAlign() &&
(ArgumentPromotionPass::isDenselyPacked(ByValTy, DL) ||
!canPaddingBeAccessed(PtrArg));
- if (IsSafeToPromote) {
- if (StructType *STy = dyn_cast<StructType>(ByValTy)) {
- if (MaxElements > 0 && STy->getNumElements() > MaxElements) {
- LLVM_DEBUG(dbgs() << "ArgPromotion disables promoting argument '"
- << PtrArg->getName()
- << "' because it would require adding more"
- << " than " << MaxElements
- << " arguments to the function.\n");
- continue;
- }
-
- SmallVector<Type *, 4> Types;
- append_range(Types, STy->elements());
-
- // If all the elements are single-value types, we can promote it.
- bool AllSimple =
- all_of(Types, [](Type *Ty) { return Ty->isSingleValueType(); });
-
- // Safe to transform, don't even bother trying to "promote" it.
- // Passing the elements as a scalar will allow sroa to hack on
- // the new alloca we introduce.
- if (AllSimple && areTypesABICompatible(Types, *F, TTI)) {
- ByValArgsToTransform.insert(PtrArg);
- continue;
- }
- }
+ if (!IsSafeToPromote) {
+ LLVM_DEBUG(dbgs() << "ArgPromotion disables passing the elements of"
+ << " the argument '" << PtrArg->getName()
+ << "' because it is not safe.\n");
+ continue;
}
-
- // Otherwise, see if we can promote the pointer to its value.
- SmallVector<OffsetAndArgPart, 4> ArgParts;
- if (findArgParts(PtrArg, DL, AAR, MaxElements, IsRecursive, ArgParts)) {
+ if (StructType *STy = dyn_cast<StructType>(ByValTy)) {
+ if (MaxElements > 0 && STy->getNumElements() > MaxElements) {
+ LLVM_DEBUG(dbgs() << "ArgPromotion disables passing the elements of"
+ << " the argument '" << PtrArg->getName()
+ << "' because it would require adding more"
+ << " than " << MaxElements
+ << " arguments to the function.\n");
+ continue;
+ }
SmallVector<Type *, 4> Types;
- for (const auto &Pair : ArgParts)
- Types.push_back(Pair.second.Ty);
+ append_range(Types, STy->elements());
- if (areTypesABICompatible(Types, *F, TTI))
- ArgsToPromote.insert({PtrArg, std::move(ArgParts)});
+ // If all the elements are single-value types, we can promote it.
+ bool AllSimple =
+ all_of(Types, [](Type *Ty) { return Ty->isSingleValueType(); });
+
+ // Safe to transform. Passing the elements as a scalar will allow sroa to
+ // hack on the new alloca we introduce.
+ if (AllSimple && areTypesABICompatible(Types, *F, TTI))
+ ByValArgsToTransform.insert(PtrArg);
}
}
diff --git a/llvm/test/Transforms/ArgumentPromotion/byval-through-pointer-promotion.ll b/llvm/test/Transforms/ArgumentPromotion/byval-through-pointer-promotion.ll
new file mode 100644
index 0000000000000..9313c79fdbd8b
--- /dev/null
+++ b/llvm/test/Transforms/ArgumentPromotion/byval-through-pointer-promotion.ll
@@ -0,0 +1,45 @@
+; RUN: opt -passes=argpromotion -S %s | FileCheck %s
+
+%struct.A = type { float, [12 x i8], i64, [8 x i8] }
+
+define internal float @callee(%struct.A* byval(%struct.A) align 32 %0) {
+; CHECK-LABEL: define {{[^@]+}}@callee
+; CHECK-SAME: (float [[ARG_0:%.*]], i64 [[ARG_1:%.*]]) {
+; CHECK-NEXT: [[SUM:%.*]] = fadd float 0.000000e+00, [[ARG_0]]
+; CHECK-NEXT: [[COEFF:%.*]] = uitofp i64 [[ARG_1]] to float
+; CHECK-NEXT: [[RES:%.*]] = fmul float [[SUM]], [[COEFF]]
+; CHECK-NEXT: ret float [[RES]]
+;
+ %2 = getelementptr inbounds %struct.A, %struct.A* %0, i32 0, i32 0
+ %3 = load float, float* %2, align 32
+ %4 = fadd float 0.000000e+00, %3
+ %5 = getelementptr inbounds %struct.A, %struct.A* %0, i32 0, i32 2
+ %6 = load i64, i64* %5, align 16
+ %7 = uitofp i64 %6 to float
+ %8 = fmul float %4, %7
+ ret float %8
+}
+
+define float @caller(float %0) {
+; CHECK-LABEL: define {{[^@]+}}@caller
+; CHECK-SAME: (float [[ARG_0:%.*]]) {
+; CHECK-NEXT: [[TMP_0:%.*]] = alloca %struct.A, align 32
+; CHECK-NEXT: [[FL_PTR_0:%.*]] = getelementptr inbounds %struct.A, %struct.A* [[TMP_0]], i32 0, i32 0
+; CHECK-NEXT: store float [[ARG_0]], float* [[FL_PTR_0]], align 32
+; CHECK-NEXT: [[I64_PTR_0:%.*]] = getelementptr inbounds %struct.A, %struct.A* [[TMP_0]], i32 0, i32 2
+; CHECK-NEXT: store i64 2, i64* [[I64_PTR_0]], align 16
+; CHECK-NEXT: [[FL_PTR_1:%.*]] = getelementptr %struct.A, %struct.A* [[TMP_0]], i64 0, i32 0
+; CHECK-NEXT: [[FL_VAL:%.*]] = load float, float* [[FL_PTR_1]], align 32
+; CHECK-NEXT: [[I64_PTR_1:%.*]] = getelementptr %struct.A, %struct.A* [[TMP_0]], i64 0, i32 2
+; CHECK-NEXT: [[I64_VAL:%.*]] = load i64, i64* [[I64_PTR_1]], align 16
+; CHECK-NEXT: [[RES:%.*]] = call noundef float @callee(float [[FL_VAL]], i64 [[I64_VAL]])
+; CHECK-NEXT: ret float [[RES]]
+;
+ %2 = alloca %struct.A, align 32
+ %3 = getelementptr inbounds %struct.A, %struct.A* %2, i32 0, i32 0
+ store float %0, float* %3, align 32
+ %4 = getelementptr inbounds %struct.A, %struct.A* %2, i32 0, i32 2
+ store i64 2, i64* %4, align 16
+ %5 = call noundef float @callee(%struct.A* byval(%struct.A) align 32 %2)
+ ret float %5
+}
diff --git a/llvm/test/Transforms/ArgumentPromotion/dbg.ll b/llvm/test/Transforms/ArgumentPromotion/dbg.ll
index 7720d750b66ba..3df10ab90bdff 100644
--- a/llvm/test/Transforms/ArgumentPromotion/dbg.ll
+++ b/llvm/test/Transforms/ArgumentPromotion/dbg.ll
@@ -21,12 +21,18 @@ define internal void @test_byval(%struct.pair* byval(%struct.pair) align 4 %P) {
; CHECK-LABEL: define {{[^@]+}}@test_byval
; CHECK-SAME: (i32 [[P_0:%.*]], i32 [[P_1:%.*]]) {
; CHECK-NEXT: [[P:%.*]] = alloca [[STRUCT_PAIR:%.*]], align 4
-; CHECK-NEXT: [[DOT0:%.*]] = getelementptr [[STRUCT_PAIR]], %struct.pair* [[P]], i32 0, i32 0
+; CHECK-NEXT: [[DOT0:%.*]] = getelementptr [[STRUCT_PAIR]], [[STRUCT_PAIR]]* [[P]], i32 0, i32 0
; CHECK-NEXT: store i32 [[P_0]], i32* [[DOT0]], align 4
-; CHECK-NEXT: [[DOT1:%.*]] = getelementptr [[STRUCT_PAIR]], %struct.pair* [[P]], i32 0, i32 1
+; CHECK-NEXT: [[DOT1:%.*]] = getelementptr [[STRUCT_PAIR]], [[STRUCT_PAIR]]* [[P]], i32 0, i32 1
; CHECK-NEXT: store i32 [[P_1]], i32* [[DOT1]], align 4
+; CHECK-NEXT: [[SINK:%.*]] = alloca i32*, align 8
+; CHECK-NEXT: [[DOT2:%.*]] = getelementptr [[STRUCT_PAIR]], [[STRUCT_PAIR]]* [[P]], i32 0, i32 0
+; CHECK-NEXT: store i32* [[DOT2]], i32** [[SINK]], align 8
; CHECK-NEXT: ret void
;
+ %1 = alloca i32*, align 8
+ %2 = getelementptr %struct.pair, %struct.pair* %P, i32 0, i32 0
+ store i32* %2, i32** %1, align 8 ; to protect from "usual" promotion
ret void
}
diff --git a/llvm/test/Transforms/ArgumentPromotion/fp80.ll b/llvm/test/Transforms/ArgumentPromotion/fp80.ll
index d791fd15a5597..a0143d31cd934 100644
--- a/llvm/test/Transforms/ArgumentPromotion/fp80.ll
+++ b/llvm/test/Transforms/ArgumentPromotion/fp80.ll
@@ -53,13 +53,21 @@ define internal x86_fp80 @UseLongDoubleSafely(%union.u* byval(%union.u) align 16
; CHECK-LABEL: define {{[^@]+}}@UseLongDoubleSafely
; CHECK-SAME: (x86_fp80 [[ARG_0:%.*]]) {
; CHECK-NEXT: [[ARG:%.*]] = alloca [[UNION_U:%.*]], align 16
-; CHECK-NEXT: [[DOT0:%.*]] = getelementptr [[UNION_U]], %union.u* [[ARG]], i32 0, i32 0
+; CHECK-NEXT: [[DOT0:%.*]] = getelementptr [[UNION_U]], [[UNION_U]]* [[ARG]], i32 0, i32 0
; CHECK-NEXT: store x86_fp80 [[ARG_0]], x86_fp80* [[DOT0]], align 16
-; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[UNION_U]], %union.u* [[ARG]], i64 0, i32 0
+; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [[UNION_U]], [[UNION_U]]* [[ARG]], i64 0, i32 0
+; CHECK-NEXT: [[IDX_P:%.*]] = alloca i64, align 8
+; CHECK-NEXT: store i64 0, i64* [[IDX_P]], align 8
+; CHECK-NEXT: [[IDX:%.*]] = load i64, i64* [[IDX_P]], align 8
+; CHECK-NEXT: [[GEP_IDX:%.*]] = getelementptr inbounds [[UNION_U]], [[UNION_U]]* [[ARG]], i64 [[IDX]], i32 0
; CHECK-NEXT: [[FP80:%.*]] = load x86_fp80, x86_fp80* [[GEP]], align 16
; CHECK-NEXT: ret x86_fp80 [[FP80]]
;
%gep = getelementptr inbounds %union.u, %union.u* %arg, i64 0, i32 0
+ %idx_slot = alloca i64, align 8
+ store i64 0, i64* %idx_slot, align 8
+ %idx = load i64, i64* %idx_slot, align 8
+ %gep_idx = getelementptr inbounds %union.u, %union.u* %arg, i64 %idx, i32 0 ; to protect from "usual" promotion
%fp80 = load x86_fp80, x86_fp80* %gep
ret x86_fp80 %fp80
}
More information about the llvm-commits
mailing list