Skip to content

Commit 871821f

Browse files
committed
[AMDGPU] Ressociate 'add (add x, y), z' to use SALU
Reassociate adds to collect scalar operands in a single instruction when possible. That will result in a scalar add followed by vector instead of two vector adds, thus better utilizing SALU. Differential Revision: https://reviews.llvm.org/D58220 llvm-svn: 354066
1 parent d3d4963 commit 871821f

File tree

4 files changed

+165
-2
lines changed

4 files changed

+165
-2
lines changed

llvm/lib/Target/AMDGPU/SIISelLowering.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8478,6 +8478,45 @@ unsigned SITargetLowering::getFusedOpcode(const SelectionDAG &DAG,
84788478
return 0;
84798479
}
84808480

8481+
// For a reassociatable opcode perform:
8482+
// op x, (op y, z) -> op (op x, z), y, if x and z are uniform
8483+
SDValue SITargetLowering::reassociateScalarOps(SDNode *N,
8484+
SelectionDAG &DAG) const {
8485+
EVT VT = N->getValueType(0);
8486+
if (VT != MVT::i32 && VT != MVT::i64)
8487+
return SDValue();
8488+
8489+
unsigned Opc = N->getOpcode();
8490+
SDValue Op0 = N->getOperand(0);
8491+
SDValue Op1 = N->getOperand(1);
8492+
8493+
if (!(Op0->isDivergent() ^ Op1->isDivergent()))
8494+
return SDValue();
8495+
8496+
if (Op0->isDivergent())
8497+
std::swap(Op0, Op1);
8498+
8499+
if (Op1.getOpcode() != Opc || !Op1.hasOneUse())
8500+
return SDValue();
8501+
8502+
SDValue Op2 = Op1.getOperand(1);
8503+
Op1 = Op1.getOperand(0);
8504+
if (!(Op1->isDivergent() ^ Op2->isDivergent()))
8505+
return SDValue();
8506+
8507+
if (Op1->isDivergent())
8508+
std::swap(Op1, Op2);
8509+
8510+
// If either operand is constant this will conflict with
8511+
// DAGCombiner::ReassociateOps().
8512+
if (isa<ConstantSDNode>(Op0) || isa<ConstantSDNode>(Op1))
8513+
return SDValue();
8514+
8515+
SDLoc SL(N);
8516+
SDValue Add1 = DAG.getNode(Opc, SL, VT, Op0, Op1);
8517+
return DAG.getNode(Opc, SL, VT, Add1, Op2);
8518+
}
8519+
84818520
static SDValue getMad64_32(SelectionDAG &DAG, const SDLoc &SL,
84828521
EVT VT,
84838522
SDValue N0, SDValue N1, SDValue N2,
@@ -8526,6 +8565,10 @@ SDValue SITargetLowering::performAddCombine(SDNode *N,
85268565
return SDValue();
85278566
}
85288567

8568+
if (SDValue V = reassociateScalarOps(N, DAG)) {
8569+
return V;
8570+
}
8571+
85298572
if (VT != MVT::i32 || !DCI.isAfterLegalizeDAG())
85308573
return SDValue();
85318574

llvm/lib/Target/AMDGPU/SIISelLowering.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ class SITargetLowering final : public AMDGPUTargetLowering {
155155
SDValue performExtractVectorEltCombine(SDNode *N, DAGCombinerInfo &DCI) const;
156156
SDValue performInsertVectorEltCombine(SDNode *N, DAGCombinerInfo &DCI) const;
157157

158+
SDValue reassociateScalarOps(SDNode *N, SelectionDAG &DAG) const;
158159
unsigned getFusedOpcode(const SelectionDAG &DAG,
159160
const SDNode *N0, const SDNode *N1) const;
160161
SDValue performAddCombine(SDNode *N, DAGCombinerInfo &DCI) const;

llvm/test/CodeGen/AMDGPU/add3.ll

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ define amdgpu_ps float @add3(i32 %a, i32 %b, i32 %c) {
2525

2626
; V_MAD_U32_U24 is given higher priority.
2727
define amdgpu_ps float @mad_no_add3(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) {
28+
; VI-LABEL: mad_no_add3:
29+
; VI: ; %bb.0:
30+
; VI-NEXT: v_mad_u32_u24 v0, v0, v1, v4
31+
; VI-NEXT: v_mad_u32_u24 v0, v2, v3, v0
32+
; VI-NEXT: ; return to shader part epilog
33+
;
2834
; GFX9-LABEL: mad_no_add3:
2935
; GFX9: ; %bb.0:
3036
; GFX9-NEXT: v_mad_u32_u24 v0, v0, v1, v4
@@ -54,13 +60,13 @@ define amdgpu_ps float @mad_no_add3(i32 %a, i32 %b, i32 %c, i32 %d, i32 %e) {
5460
define amdgpu_ps float @add3_vgpr_b(i32 inreg %a, i32 %b, i32 inreg %c) {
5561
; VI-LABEL: add3_vgpr_b:
5662
; VI: ; %bb.0:
57-
; VI-NEXT: v_add_u32_e32 v0, vcc, s2, v0
63+
; VI-NEXT: s_add_i32 s3, s3, s2
5864
; VI-NEXT: v_add_u32_e32 v0, vcc, s3, v0
5965
; VI-NEXT: ; return to shader part epilog
6066
;
6167
; GFX9-LABEL: add3_vgpr_b:
6268
; GFX9: ; %bb.0:
63-
; GFX9-NEXT: v_add_u32_e32 v0, s2, v0
69+
; GFX9-NEXT: s_add_i32 s3, s3, s2
6470
; GFX9-NEXT: v_add_u32_e32 v0, s3, v0
6571
; GFX9-NEXT: ; return to shader part epilog
6672
%x = add i32 %a, %b
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
; RUN: llc -mtriple=amdgcn -mcpu=tonga -verify-machineinstrs < %s | FileCheck -check-prefixes=GCN,GFX8 %s
2+
; RUN: llc -mtriple=amdgcn -mcpu=gfx900 -verify-machineinstrs < %s | FileCheck -check-prefixes=GCN,GFX9 %s
3+
4+
; GCN-LABEL: reassoc_i32:
5+
; GCN: s_add_i32 [[ADD1:s[0-9]+]], s{{[0-9]+}}, s{{[0-9]+}}
6+
; GFX8: v_add_u32_e32 v{{[0-9]+}}, vcc, [[ADD1]], v{{[0-9]+}}
7+
; GFX9: v_add_u32_e32 v{{[0-9]+}}, [[ADD1]], v{{[0-9]+}}
8+
define amdgpu_kernel void @reassoc_i32(i32 addrspace(1)* %arg, i32 %x, i32 %y) {
9+
bb:
10+
%tid = tail call i32 @llvm.amdgcn.workitem.id.x()
11+
%add1 = add i32 %x, %tid
12+
%add2 = add i32 %add1, %y
13+
store i32 %add2, i32 addrspace(1)* %arg, align 4
14+
ret void
15+
}
16+
17+
; GCN-LABEL: reassoc_i32_swap_arg_order:
18+
; GCN: s_add_i32 [[ADD1:s[0-9]+]], s{{[0-9]+}}, s{{[0-9]+}}
19+
; GFX8: v_add_u32_e32 v{{[0-9]+}}, vcc, [[ADD1]], v{{[0-9]+}}
20+
; GFX9: v_add_u32_e32 v{{[0-9]+}}, [[ADD1]], v{{[0-9]+}}
21+
define amdgpu_kernel void @reassoc_i32_swap_arg_order(i32 addrspace(1)* %arg, i32 %x, i32 %y) {
22+
bb:
23+
%tid = tail call i32 @llvm.amdgcn.workitem.id.x()
24+
%add1 = add i32 %tid, %x
25+
%add2 = add i32 %y, %add1
26+
store i32 %add2, i32 addrspace(1)* %arg, align 4
27+
ret void
28+
}
29+
30+
; GCN-LABEL: reassoc_i64:
31+
; GCN: s_add_u32 [[ADD1L:s[0-9]+]], s{{[0-9]+}}, s{{[0-9]+}}
32+
; GCN: s_addc_u32 [[ADD1H:s[0-9]+]], s{{[0-9]+}}, s{{[0-9]+}}
33+
; GFX8-DAG: v_add_u32_e32 v{{[0-9]+}}, vcc, [[ADD1L]], v{{[0-9]+}}
34+
; GFX9-DAG: v_add_co_u32_e32 v{{[0-9]+}}, vcc, [[ADD1L]], v{{[0-9]+}}
35+
; GCN-DAG: v_mov_b32_e32 [[VADD1H:v[0-9]+]], [[ADD1H]]
36+
; GFX8: v_addc_u32_e32 v{{[0-9]+}}, vcc, 0, [[VADD1H]], vcc
37+
; GFX9: v_addc_co_u32_e32 v{{[0-9]+}}, vcc, 0, [[VADD1H]], vcc
38+
define amdgpu_kernel void @reassoc_i64(i64 addrspace(1)* %arg, i64 %x, i64 %y) {
39+
bb:
40+
%tid32 = tail call i32 @llvm.amdgcn.workitem.id.x()
41+
%tid = zext i32 %tid32 to i64
42+
%add1 = add i64 %x, %tid
43+
%add2 = add i64 %add1, %y
44+
store i64 %add2, i64 addrspace(1)* %arg, align 8
45+
ret void
46+
}
47+
48+
; GCN-LABEL: reassoc_v2i32:
49+
; GCN: s_add_i32 [[ADD1:s[0-9]+]], s{{[0-9]+}}, s{{[0-9]+}}
50+
; GCN: s_add_i32 [[ADD2:s[0-9]+]], s{{[0-9]+}}, s{{[0-9]+}}
51+
; GFX8: v_add_u32_e32 v{{[0-9]+}}, vcc, [[ADD1]], v{{[0-9]+}}
52+
; GFX8: v_add_u32_e32 v{{[0-9]+}}, vcc, [[ADD2]], v{{[0-9]+}}
53+
; GFX9: v_add_u32_e32 v{{[0-9]+}}, [[ADD1]], v{{[0-9]+}}
54+
; GFX9: v_add_u32_e32 v{{[0-9]+}}, [[ADD2]], v{{[0-9]+}}
55+
define amdgpu_kernel void @reassoc_v2i32(<2 x i32> addrspace(1)* %arg, <2 x i32> %x, <2 x i32> %y) {
56+
bb:
57+
%t1 = tail call i32 @llvm.amdgcn.workitem.id.x()
58+
%t2 = tail call i32 @llvm.amdgcn.workitem.id.y()
59+
%v1 = insertelement <2 x i32> undef, i32 %t1, i32 0
60+
%v2 = insertelement <2 x i32> %v1, i32 %t2, i32 1
61+
%add1 = add <2 x i32> %x, %v2
62+
%add2 = add <2 x i32> %add1, %y
63+
store <2 x i32> %add2, <2 x i32> addrspace(1)* %arg, align 4
64+
ret void
65+
}
66+
67+
; GCN-LABEL: reassoc_i32_nuw:
68+
; GCN: s_add_i32 [[ADD1:s[0-9]+]], s{{[0-9]+}}, s{{[0-9]+}}
69+
; GFX8: v_add_u32_e32 v{{[0-9]+}}, vcc, [[ADD1]], v{{[0-9]+}}
70+
; GFX9: v_add_u32_e32 v{{[0-9]+}}, [[ADD1]], v{{[0-9]+}}
71+
define amdgpu_kernel void @reassoc_i32_nuw(i32 addrspace(1)* %arg, i32 %x, i32 %y) {
72+
bb:
73+
%tid = tail call i32 @llvm.amdgcn.workitem.id.x()
74+
%add1 = add i32 %x, %tid
75+
%add2 = add nuw i32 %add1, %y
76+
store i32 %add2, i32 addrspace(1)* %arg, align 4
77+
ret void
78+
}
79+
80+
; GCN-LABEL: reassoc_i32_multiuse:
81+
; GFX8: v_add_u32_e32 [[ADD1:v[0-9]+]], vcc, s{{[0-9]+}}, v{{[0-9]+}}
82+
; GFX9: v_add_u32_e32 [[ADD1:v[0-9]+]], s{{[0-9]+}}, v{{[0-9]+}}
83+
; GFX8: v_add_u32_e32 v{{[0-9]+}}, vcc, s{{[0-9]+}}, [[ADD1]]
84+
; GFX9: v_add_u32_e32 v{{[0-9]+}}, s{{[0-9]+}}, [[ADD1]]
85+
define amdgpu_kernel void @reassoc_i32_multiuse(i32 addrspace(1)* %arg, i32 %x, i32 %y) {
86+
bb:
87+
%tid = tail call i32 @llvm.amdgcn.workitem.id.x()
88+
%add1 = add i32 %x, %tid
89+
%add2 = add i32 %add1, %y
90+
store volatile i32 %add1, i32 addrspace(1)* %arg, align 4
91+
store volatile i32 %add2, i32 addrspace(1)* %arg, align 4
92+
ret void
93+
}
94+
95+
; TODO: This should be reassociated as well, however it is disabled to avoid endless
96+
; loop since DAGCombiner::ReassociateOps() reverts the reassociation.
97+
; GCN-LABEL: reassoc_i32_const:
98+
; GFX8: v_add_u32_e32 [[ADD1:v[0-9]+]], vcc, 42, v{{[0-9]+}}
99+
; GFX9: v_add_u32_e32 [[ADD1:v[0-9]+]], 42, v{{[0-9]+}}
100+
; GFX8: v_add_u32_e32 v{{[0-9]+}}, vcc, s{{[0-9]+}}, [[ADD1]]
101+
; GFX9: v_add_u32_e32 v{{[0-9]+}}, s{{[0-9]+}}, [[ADD1]]
102+
define amdgpu_kernel void @reassoc_i32_const(i32 addrspace(1)* %arg, i32 %x) {
103+
bb:
104+
%tid = tail call i32 @llvm.amdgcn.workitem.id.x()
105+
%add1 = add i32 %tid, 42
106+
%add2 = add i32 %add1, %x
107+
store volatile i32 %add1, i32 addrspace(1)* %arg, align 4
108+
store volatile i32 %add2, i32 addrspace(1)* %arg, align 4
109+
ret void
110+
}
111+
112+
declare i32 @llvm.amdgcn.workitem.id.x()
113+
declare i32 @llvm.amdgcn.workitem.id.y()

0 commit comments

Comments
 (0)