Skip to content

Commit f9edcfb

Browse files
author
Thorsten Schütt
committed
[GlobalIsel] Combine trunc of binop
trunc (binop X, C) --> binop (trunc X, trunc C) Try to narrow the width of math or bitwise logic instructions by pulling a truncate ahead of binary operators. Vx and Nx cores consider 32-bit and 64-bit basic arithmetic equal in costs.
1 parent 23a26e7 commit f9edcfb

18 files changed

+3478
-3108
lines changed

llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,12 @@ class CombinerHelper {
831831
/// Combine ors.
832832
bool matchOr(MachineInstr &MI, BuildFnTy &MatchInfo);
833833

834+
/// trunc (binop X, C) --> binop (trunc X, trunc C).
835+
bool matchNarrowBinop(const MachineInstr &TruncMI,
836+
const MachineInstr &BinopMI, BuildFnTy &MatchInfo);
837+
838+
bool matchCastOfInteger(const MachineInstr &CastMI, APInt &MatchInfo);
839+
834840
/// Combine addos.
835841
bool matchAddOverflow(MachineInstr &MI, BuildFnTy &MatchInfo);
836842

llvm/include/llvm/Target/GlobalISel/Combine.td

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1867,6 +1867,33 @@ class buildvector_of_opcode<Instruction castOpcode> : GICombineRule <
18671867

18681868
def buildvector_of_truncate : buildvector_of_opcode<G_TRUNC>;
18691869

1870+
// narrow binop.
1871+
// trunc (binop X, C) --> binop (trunc X, trunc C)
1872+
class narrow_binop_opcode<Instruction binopOpcode> : GICombineRule <
1873+
(defs root:$root, build_fn_matchinfo:$matchinfo),
1874+
(match (G_CONSTANT $const, $imm),
1875+
(binopOpcode $binop, $x, $const):$Binop,
1876+
(G_TRUNC $root, $binop):$Trunc,
1877+
[{ return Helper.matchNarrowBinop(*${Trunc}, *${Binop}, ${matchinfo}); }]),
1878+
(apply [{ Helper.applyBuildFn(*${Trunc}, ${matchinfo}); }])>;
1879+
1880+
def narrow_binop_add : narrow_binop_opcode<G_ADD>;
1881+
def narrow_binop_sub : narrow_binop_opcode<G_SUB>;
1882+
def narrow_binop_mul : narrow_binop_opcode<G_MUL>;
1883+
def narrow_binop_and : narrow_binop_opcode<G_AND>;
1884+
def narrow_binop_or : narrow_binop_opcode<G_OR>;
1885+
def narrow_binop_xor : narrow_binop_opcode<G_XOR>;
1886+
1887+
// Cast of integer.
1888+
class integer_of_opcode<Instruction castOpcode> : GICombineRule <
1889+
(defs root:$root, apint_matchinfo:$matchinfo),
1890+
(match (G_CONSTANT $int, $imm),
1891+
(castOpcode $root, $int):$Cast,
1892+
[{ return Helper.matchCastOfInteger(*${Cast}, ${matchinfo}); }]),
1893+
(apply [{ Helper.replaceInstWithConstant(*${Cast}, ${matchinfo}); }])>;
1894+
1895+
def integer_of_truncate : integer_of_opcode<G_TRUNC>;
1896+
18701897
def cast_combines: GICombineGroup<[
18711898
truncate_of_zext,
18721899
truncate_of_sext,
@@ -1881,7 +1908,14 @@ def cast_combines: GICombineGroup<[
18811908
anyext_of_anyext,
18821909
anyext_of_zext,
18831910
anyext_of_sext,
1884-
buildvector_of_truncate
1911+
buildvector_of_truncate,
1912+
narrow_binop_add,
1913+
narrow_binop_sub,
1914+
narrow_binop_mul,
1915+
narrow_binop_and,
1916+
narrow_binop_or,
1917+
narrow_binop_xor,
1918+
integer_of_truncate
18851919
]>;
18861920

18871921

llvm/lib/CodeGen/GlobalISel/CombinerHelperCasts.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,3 +313,49 @@ bool CombinerHelper::matchCastOfBuildVector(const MachineInstr &CastMI,
313313

314314
return true;
315315
}
316+
317+
bool CombinerHelper::matchNarrowBinop(const MachineInstr &TruncMI,
318+
const MachineInstr &BinopMI,
319+
BuildFnTy &MatchInfo) {
320+
const GTrunc *Trunc = cast<GTrunc>(&TruncMI);
321+
const GBinOp *BinOp = cast<GBinOp>(&BinopMI);
322+
323+
if (!MRI.hasOneNonDBGUse(BinOp->getReg(0)))
324+
return false;
325+
326+
Register Dst = Trunc->getReg(0);
327+
LLT DstTy = MRI.getType(Dst);
328+
329+
// Is narrow binop legal?
330+
if (!isLegalOrBeforeLegalizer({BinOp->getOpcode(), {DstTy}}))
331+
return false;
332+
333+
MatchInfo = [=](MachineIRBuilder &B) {
334+
auto LHS = B.buildTrunc(DstTy, BinOp->getLHSReg());
335+
auto RHS = B.buildTrunc(DstTy, BinOp->getRHSReg());
336+
B.buildInstr(BinOp->getOpcode(), {Dst}, {LHS, RHS});
337+
};
338+
339+
return true;
340+
}
341+
342+
bool CombinerHelper::matchCastOfInteger(const MachineInstr &CastMI,
343+
APInt &MatchInfo) {
344+
const GExtOrTruncOp *Cast = cast<GExtOrTruncOp>(&CastMI);
345+
346+
APInt Input = getIConstantFromReg(Cast->getSrcReg(), MRI);
347+
348+
LLT DstTy = MRI.getType(Cast->getReg(0));
349+
350+
if (!isConstantLegalOrBeforeLegalizer(DstTy))
351+
return false;
352+
353+
switch (Cast->getOpcode()) {
354+
case TargetOpcode::G_TRUNC: {
355+
MatchInfo = Input.trunc(DstTy.getScalarSizeInBits());
356+
return true;
357+
}
358+
default:
359+
return false;
360+
}
361+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc -o - -mtriple=aarch64-unknown-unknown -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs %s | FileCheck %s --check-prefixes=CHECK
3+
4+
---
5+
name: test_combine_trunc_xor_i64
6+
body: |
7+
bb.1:
8+
; CHECK-LABEL: name: test_combine_trunc_xor_i64
9+
; CHECK: %lhs:_(s64) = COPY $x0
10+
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC %lhs(s64)
11+
; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 5
12+
; CHECK-NEXT: %small:_(s32) = G_XOR [[TRUNC]], [[C]]
13+
; CHECK-NEXT: $w0 = COPY %small(s32)
14+
%lhs:_(s64) = COPY $x0
15+
%rhs:_(s64) = G_CONSTANT i64 5
16+
%res:_(s64) = G_XOR %lhs, %rhs
17+
%small:_(s32) = G_TRUNC %res(s64)
18+
$w0 = COPY %small(s32)
19+
...
20+
---
21+
name: test_combine_trunc_add_i64
22+
body: |
23+
bb.1:
24+
; CHECK-LABEL: name: test_combine_trunc_add_i64
25+
; CHECK: %lhs:_(s64) = COPY $x0
26+
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC %lhs(s64)
27+
; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 5
28+
; CHECK-NEXT: %small:_(s32) = G_ADD [[TRUNC]], [[C]]
29+
; CHECK-NEXT: $w0 = COPY %small(s32)
30+
%lhs:_(s64) = COPY $x0
31+
%rhs:_(s64) = G_CONSTANT i64 5
32+
%res:_(s64) = G_ADD %lhs, %rhs
33+
%small:_(s32) = G_TRUNC %res(s64)
34+
$w0 = COPY %small(s32)
35+
...
36+
---
37+
name: test_combine_trunc_mul_i64
38+
body: |
39+
bb.1:
40+
; CHECK-LABEL: name: test_combine_trunc_mul_i64
41+
; CHECK: %lhs:_(s64) = COPY $x0
42+
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC %lhs(s64)
43+
; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 5
44+
; CHECK-NEXT: %small:_(s32) = G_MUL [[TRUNC]], [[C]]
45+
; CHECK-NEXT: $w0 = COPY %small(s32)
46+
%lhs:_(s64) = COPY $x0
47+
%rhs:_(s64) = G_CONSTANT i64 5
48+
%res:_(s64) = G_MUL %lhs, %rhs
49+
%small:_(s32) = G_TRUNC %res(s64)
50+
$w0 = COPY %small(s32)
51+
...
52+
---
53+
name: test_combine_trunc_and_i64
54+
body: |
55+
bb.1:
56+
; CHECK-LABEL: name: test_combine_trunc_and_i64
57+
; CHECK: %lhs:_(s64) = COPY $x0
58+
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC %lhs(s64)
59+
; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 5
60+
; CHECK-NEXT: %small:_(s32) = G_AND [[TRUNC]], [[C]]
61+
; CHECK-NEXT: $w0 = COPY %small(s32)
62+
%lhs:_(s64) = COPY $x0
63+
%rhs:_(s64) = G_CONSTANT i64 5
64+
%res:_(s64) = G_AND %lhs, %rhs
65+
%small:_(s32) = G_TRUNC %res(s64)
66+
$w0 = COPY %small(s32)
67+
...
68+
---
69+
name: test_combine_trunc_or_i64
70+
body: |
71+
bb.1:
72+
; CHECK-LABEL: name: test_combine_trunc_or_i64
73+
; CHECK: %lhs:_(s64) = COPY $x0
74+
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC %lhs(s64)
75+
; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 5
76+
; CHECK-NEXT: %small:_(s32) = G_OR [[TRUNC]], [[C]]
77+
; CHECK-NEXT: $w0 = COPY %small(s32)
78+
%lhs:_(s64) = COPY $x0
79+
%rhs:_(s64) = G_CONSTANT i64 5
80+
%res:_(s64) = G_OR %lhs, %rhs
81+
%small:_(s32) = G_TRUNC %res(s64)
82+
$w0 = COPY %small(s32)
83+
...
84+
---
85+
name: test_combine_trunc_sub_i128
86+
body: |
87+
bb.1:
88+
; CHECK-LABEL: name: test_combine_trunc_sub_i128
89+
; CHECK: %lhs:_(s128) = COPY $q0
90+
; CHECK-NEXT: [[TRUNC:%[0-9]+]]:_(s32) = G_TRUNC %lhs(s128)
91+
; CHECK-NEXT: [[C:%[0-9]+]]:_(s32) = G_CONSTANT i32 5
92+
; CHECK-NEXT: %small:_(s32) = G_SUB [[TRUNC]], [[C]]
93+
; CHECK-NEXT: $w0 = COPY %small(s32)
94+
%lhs:_(s128) = COPY $q0
95+
%rhs:_(s128) = G_CONSTANT i128 5
96+
%res:_(s128) = G_SUB %lhs, %rhs
97+
%small:_(s32) = G_TRUNC %res(s128)
98+
$w0 = COPY %small(s32)
99+
...
100+
---
101+
name: test_combine_trunc_sub_i128_multi_use
102+
body: |
103+
bb.1:
104+
; CHECK-LABEL: name: test_combine_trunc_sub_i128_multi_use
105+
; CHECK: %lhs:_(s128) = COPY $q0
106+
; CHECK-NEXT: %rhs:_(s128) = G_CONSTANT i128 5
107+
; CHECK-NEXT: %res:_(s128) = G_SUB %lhs, %rhs
108+
; CHECK-NEXT: %small:_(s32) = G_TRUNC %res(s128)
109+
; CHECK-NEXT: $q0 = COPY %res(s128)
110+
; CHECK-NEXT: $w0 = COPY %small(s32)
111+
%lhs:_(s128) = COPY $q0
112+
%rhs:_(s128) = G_CONSTANT i128 5
113+
%res:_(s128) = G_SUB %lhs, %rhs
114+
%small:_(s32) = G_TRUNC %res(s128)
115+
$q0 = COPY %res(s128)
116+
$w0 = COPY %small(s32)
117+
...
118+
---
119+
name: test_combine_trunc_xor_vector_pattern_did_not_match
120+
body: |
121+
bb.1:
122+
; CHECK-LABEL: name: test_combine_trunc_xor_vector_pattern_did_not_match
123+
; CHECK: %arg1:_(s64) = COPY $x0
124+
; CHECK-NEXT: %arg2:_(s64) = COPY $x0
125+
; CHECK-NEXT: %lhs:_(<2 x s64>) = G_BUILD_VECTOR %arg1(s64), %arg2(s64)
126+
; CHECK-NEXT: %rhs:_(<2 x s64>) = G_BUILD_VECTOR %arg1(s64), %arg2(s64)
127+
; CHECK-NEXT: %res:_(<2 x s64>) = G_XOR %lhs, %rhs
128+
; CHECK-NEXT: %small:_(<2 x s16>) = G_TRUNC %res(<2 x s64>)
129+
; CHECK-NEXT: $w0 = COPY %small(<2 x s16>)
130+
%arg1:_(s64) = COPY $x0
131+
%arg2:_(s64) = COPY $x0
132+
%lhs:_(<2 x s64>) = G_BUILD_VECTOR %arg1(s64), %arg2(s64)
133+
%rhs:_(<2 x s64>) = G_BUILD_VECTOR %arg1(s64), %arg2(s64)
134+
%res:_(<2 x s64>) = G_XOR %lhs, %rhs
135+
%small:_(<2 x s16>) = G_TRUNC %res(<2 x s64>)
136+
$w0 = COPY %small(<2 x s16>)

0 commit comments

Comments
 (0)