Skip to content

Commit 930b5b5

Browse files
[ConstantHoisting] Add a TTI hook to prevent hoisting. (#69004)
Code generation can sometimes simplify expensive operations when an operand is constant. An example of this is divides on AArch64 where they can be rewritten using a cheaper sequence of multiplies and subtracts. Doing this is often better than hoisting expensive constants which are likely to be hoisted by MachineLICM anyway.
1 parent 8d7c979 commit 930b5b5

File tree

6 files changed

+163
-10
lines changed

6 files changed

+163
-10
lines changed

llvm/include/llvm/Analysis/TargetTransformInfo.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,16 @@ class TargetTransformInfo {
10021002
/// more beneficial constant hoisting is).
10031003
InstructionCost getIntImmCodeSizeCost(unsigned Opc, unsigned Idx,
10041004
const APInt &Imm, Type *Ty) const;
1005+
1006+
/// It can be advantageous to detach complex constants from their uses to make
1007+
/// their generation cheaper. This hook allows targets to report when such
1008+
/// transformations might negatively effect the code generation of the
1009+
/// underlying operation. The motivating example is divides whereby hoisting
1010+
/// constants prevents the code generator's ability to transform them into
1011+
/// combinations of simpler operations.
1012+
bool preferToKeepConstantsAttached(const Instruction &Inst,
1013+
const Function &Fn) const;
1014+
10051015
/// @}
10061016

10071017
/// \name Vector Target Information
@@ -1873,6 +1883,8 @@ class TargetTransformInfo::Concept {
18731883
virtual InstructionCost getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx,
18741884
const APInt &Imm, Type *Ty,
18751885
TargetCostKind CostKind) = 0;
1886+
virtual bool preferToKeepConstantsAttached(const Instruction &Inst,
1887+
const Function &Fn) const = 0;
18761888
virtual unsigned getNumberOfRegisters(unsigned ClassID) const = 0;
18771889
virtual unsigned getRegisterClassForType(bool Vector,
18781890
Type *Ty = nullptr) const = 0;
@@ -2430,6 +2442,10 @@ class TargetTransformInfo::Model final : public TargetTransformInfo::Concept {
24302442
TargetCostKind CostKind) override {
24312443
return Impl.getIntImmCostIntrin(IID, Idx, Imm, Ty, CostKind);
24322444
}
2445+
bool preferToKeepConstantsAttached(const Instruction &Inst,
2446+
const Function &Fn) const override {
2447+
return Impl.preferToKeepConstantsAttached(Inst, Fn);
2448+
}
24332449
unsigned getNumberOfRegisters(unsigned ClassID) const override {
24342450
return Impl.getNumberOfRegisters(ClassID);
24352451
}

llvm/include/llvm/Analysis/TargetTransformInfoImpl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,11 @@ class TargetTransformInfoImplBase {
427427
return TTI::TCC_Free;
428428
}
429429

430+
bool preferToKeepConstantsAttached(const Instruction &Inst,
431+
const Function &Fn) const {
432+
return false;
433+
}
434+
430435
unsigned getNumberOfRegisters(unsigned ClassID) const { return 8; }
431436

432437
unsigned getRegisterClassForType(bool Vector, Type *Ty = nullptr) const {

llvm/include/llvm/CodeGen/BasicTTIImpl.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,25 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
545545
return TargetTransformInfo::TCC_Expensive;
546546
}
547547

548+
bool preferToKeepConstantsAttached(const Instruction &Inst,
549+
const Function &Fn) const {
550+
switch (Inst.getOpcode()) {
551+
default:
552+
break;
553+
case Instruction::SDiv:
554+
case Instruction::SRem:
555+
case Instruction::UDiv:
556+
case Instruction::URem: {
557+
if (!isa<ConstantInt>(Inst.getOperand(1)))
558+
return false;
559+
EVT VT = getTLI()->getValueType(DL, Inst.getType());
560+
return !getTLI()->isIntDivCheap(VT, Fn.getAttributes());
561+
}
562+
};
563+
564+
return false;
565+
}
566+
548567
unsigned getInliningThresholdMultiplier() const { return 1; }
549568
unsigned adjustInliningThreshold(const CallBase *CB) { return 0; }
550569
unsigned getCallerAllocaCost(const CallBase *CB, const AllocaInst *AI) const {

llvm/lib/Analysis/TargetTransformInfo.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -682,6 +682,11 @@ TargetTransformInfo::getIntImmCostIntrin(Intrinsic::ID IID, unsigned Idx,
682682
return Cost;
683683
}
684684

685+
bool TargetTransformInfo::preferToKeepConstantsAttached(
686+
const Instruction &Inst, const Function &Fn) const {
687+
return TTIImpl->preferToKeepConstantsAttached(Inst, Fn);
688+
}
689+
685690
unsigned TargetTransformInfo::getNumberOfRegisters(unsigned ClassID) const {
686691
return TTIImpl->getNumberOfRegisters(ClassID);
687692
}

llvm/lib/Transforms/Scalar/ConstantHoisting.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,8 @@ void ConstantHoistingPass::collectConstantCandidates(Function &Fn) {
523523
if (!DT->isReachableFromEntry(&BB))
524524
continue;
525525
for (Instruction &Inst : BB)
526-
collectConstantCandidates(ConstCandMap, &Inst);
526+
if (!TTI->preferToKeepConstantsAttached(Inst, Fn))
527+
collectConstantCandidates(ConstCandMap, &Inst);
527528
}
528529
}
529530

Lines changed: 116 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,134 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
12
; RUN: opt -mtriple=arm64-darwin-unknown -S -passes=consthoist < %s | FileCheck %s
23

3-
define i128 @test1(i128 %a) nounwind {
4-
; CHECK-LABEL: test1
5-
; CHECK: %const = bitcast i128 12297829382473034410122878 to i128
4+
define i128 @test1(i128 %a) {
5+
; CHECK-LABEL: define i128 @test1(
6+
; CHECK-SAME: i128 [[A:%.*]]) {
7+
; CHECK-NEXT: [[CONST:%.*]] = bitcast i128 12297829382473034410122878 to i128
8+
; CHECK-NEXT: [[TMP1:%.*]] = add i128 [[A]], [[CONST]]
9+
; CHECK-NEXT: [[TMP2:%.*]] = add i128 [[TMP1]], [[CONST]]
10+
; CHECK-NEXT: ret i128 [[TMP2]]
11+
;
612
%1 = add i128 %a, 12297829382473034410122878
713
%2 = add i128 %1, 12297829382473034410122878
814
ret i128 %2
915
}
1016

1117
; Check that we don't hoist large, but cheap constants
12-
define i512 @test2(i512 %a) nounwind {
13-
; CHECK-LABEL: test2
14-
; CHECK-NOT: %const = bitcast i512 7 to i512
18+
define i512 @test2(i512 %a) {
19+
; CHECK-LABEL: define i512 @test2(
20+
; CHECK-SAME: i512 [[A:%.*]]) {
21+
; CHECK-NEXT: [[TMP1:%.*]] = and i512 [[A]], 7
22+
; CHECK-NEXT: [[TMP2:%.*]] = or i512 [[TMP1]], 7
23+
; CHECK-NEXT: ret i512 [[TMP2]]
24+
;
1525
%1 = and i512 %a, 7
1626
%2 = or i512 %1, 7
1727
ret i512 %2
1828
}
1929

2030
; Check that we don't hoist the shift value of a shift instruction.
21-
define i512 @test3(i512 %a) nounwind {
22-
; CHECK-LABEL: test3
23-
; CHECK-NOT: %const = bitcast i512 504 to i512
31+
define i512 @test3(i512 %a) {
32+
; CHECK-LABEL: define i512 @test3(
33+
; CHECK-SAME: i512 [[A:%.*]]) {
34+
; CHECK-NEXT: [[TMP1:%.*]] = shl i512 [[A]], 504
35+
; CHECK-NEXT: [[TMP2:%.*]] = ashr i512 [[TMP1]], 504
36+
; CHECK-NEXT: ret i512 [[TMP2]]
37+
;
2438
%1 = shl i512 %a, 504
2539
%2 = ashr i512 %1, 504
2640
ret i512 %2
2741
}
42+
43+
; Ensure the code generator has the information necessary to simply sdiv.
44+
define i64 @sdiv(i64 %a) {
45+
; CHECK-LABEL: define i64 @sdiv(
46+
; CHECK-SAME: i64 [[A:%.*]]) {
47+
; CHECK-NEXT: [[TMP1:%.*]] = sdiv i64 [[A]], 4294967087
48+
; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], 4294967087
49+
; CHECK-NEXT: ret i64 [[TMP2]]
50+
;
51+
%1 = sdiv i64 %a, 4294967087
52+
%2 = add i64 %1, 4294967087
53+
ret i64 %2
54+
}
55+
56+
; Ensure the code generator has the information necessary to simply srem.
57+
define i64 @srem(i64 %a) {
58+
; CHECK-LABEL: define i64 @srem(
59+
; CHECK-SAME: i64 [[A:%.*]]) {
60+
; CHECK-NEXT: [[TMP1:%.*]] = srem i64 [[A]], 4294967087
61+
; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], 4294967087
62+
; CHECK-NEXT: ret i64 [[TMP2]]
63+
;
64+
%1 = srem i64 %a, 4294967087
65+
%2 = add i64 %1, 4294967087
66+
ret i64 %2
67+
}
68+
69+
; Ensure the code generator has the information necessary to simply udiv.
70+
define i64 @udiv(i64 %a) {
71+
; CHECK-LABEL: define i64 @udiv(
72+
; CHECK-SAME: i64 [[A:%.*]]) {
73+
; CHECK-NEXT: [[TMP1:%.*]] = udiv i64 [[A]], 4294967087
74+
; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], 4294967087
75+
; CHECK-NEXT: ret i64 [[TMP2]]
76+
;
77+
%1 = udiv i64 %a, 4294967087
78+
%2 = add i64 %1, 4294967087
79+
ret i64 %2
80+
}
81+
82+
; Ensure the code generator has the information necessary to simply urem.
83+
define i64 @urem(i64 %a) {
84+
; CHECK-LABEL: define i64 @urem(
85+
; CHECK-SAME: i64 [[A:%.*]]) {
86+
; CHECK-NEXT: [[TMP1:%.*]] = urem i64 [[A]], 4294967087
87+
; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], 4294967087
88+
; CHECK-NEXT: ret i64 [[TMP2]]
89+
;
90+
%1 = urem i64 %a, 4294967087
91+
%2 = add i64 %1, 4294967087
92+
ret i64 %2
93+
}
94+
95+
; Code generator will not decompose divide like operations when the divisor is
96+
; no a constant.
97+
define i64 @sdiv_non_const_divisor(i64 %a) {
98+
; CHECK-LABEL: define i64 @sdiv_non_const_divisor(
99+
; CHECK-SAME: i64 [[A:%.*]]) {
100+
; CHECK-NEXT: [[CONST:%.*]] = bitcast i64 4294967087 to i64
101+
; CHECK-NEXT: [[TMP1:%.*]] = sdiv i64 [[CONST]], [[A]]
102+
; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], [[CONST]]
103+
; CHECK-NEXT: ret i64 [[TMP2]]
104+
;
105+
%1 = sdiv i64 4294967087, %a
106+
%2 = add i64 %1, 4294967087
107+
ret i64 %2
108+
}
109+
110+
; Code generator emits divide instructions when optimising for size.
111+
define i64 @sdiv_minsize(i64 %a) minsize {
112+
; CHECK-LABEL: define i64 @sdiv_minsize(
113+
; CHECK-SAME: i64 [[A:%.*]]) #[[ATTR0:[0-9]+]] {
114+
; CHECK-NEXT: [[CONST:%.*]] = bitcast i64 4294967087 to i64
115+
; CHECK-NEXT: [[TMP1:%.*]] = sdiv i64 [[A]], [[CONST]]
116+
; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[TMP1]], [[CONST]]
117+
; CHECK-NEXT: ret i64 [[TMP2]]
118+
;
119+
%1 = sdiv i64 %a, 4294967087
120+
%2 = add i64 %1, 4294967087
121+
ret i64 %2
122+
}
123+
124+
define <2 x i64> @sdiv_v2i64(<2 x i64> %a) {
125+
; CHECK-LABEL: define <2 x i64> @sdiv_v2i64(
126+
; CHECK-SAME: <2 x i64> [[A:%.*]]) {
127+
; CHECK-NEXT: [[TMP1:%.*]] = sdiv <2 x i64> [[A]], <i64 4294967087, i64 4294967087>
128+
; CHECK-NEXT: [[TMP2:%.*]] = add <2 x i64> [[TMP1]], <i64 4294967087, i64 4294967087>
129+
; CHECK-NEXT: ret <2 x i64> [[TMP2]]
130+
;
131+
%1 = sdiv <2 x i64> %a, <i64 4294967087, i64 4294967087>
132+
%2 = add <2 x i64> %1, <i64 4294967087, i64 4294967087>
133+
ret <2 x i64> %2
134+
}

0 commit comments

Comments
 (0)