Skip to content

Commit 0559458

Browse files
VyacheslavLevytskyyAlexisPerry
authored andcommitted
[SPIR-V]: Improve pattern matching to recognize a composite constant to be a constant (llvm#96286)
This PR is to fix llvm#96285 by: * improve pattern matching to recognize an aggregate constant to be a constant * do not emit Bitcast for an aggregate type
1 parent 19bec54 commit 0559458

File tree

7 files changed

+224
-12
lines changed

7 files changed

+224
-12
lines changed

llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -670,10 +670,8 @@ void SPIRVEmitIntrinsics::preprocessCompositeConstants(IRBuilder<> &B) {
670670
AggrConst = cast<Constant>(COp);
671671
ResTy = B.getInt32Ty();
672672
} else if (auto *COp = dyn_cast<ConstantAggregateZero>(Op)) {
673-
if (!Op->getType()->isVectorTy()) {
674-
AggrConst = cast<Constant>(COp);
675-
ResTy = B.getInt32Ty();
676-
}
673+
AggrConst = cast<Constant>(COp);
674+
ResTy = Op->getType()->isVectorTy() ? COp->getType() : B.getInt32Ty();
677675
}
678676
if (AggrConst) {
679677
SmallVector<Value *> Args;
@@ -1260,8 +1258,7 @@ void SPIRVEmitIntrinsics::processInstrAfterVisit(Instruction *I,
12601258
}
12611259
bool IsPhi = isa<PHINode>(I), BPrepared = false;
12621260
for (const auto &Op : I->operands()) {
1263-
if ((isa<ConstantAggregateZero>(Op) && Op->getType()->isVectorTy()) ||
1264-
isa<PHINode>(I) || isa<SwitchInst>(I))
1261+
if (isa<PHINode>(I) || isa<SwitchInst>(I))
12651262
TrackConstants = false;
12661263
if ((isa<ConstantData>(Op) || isa<ConstantExpr>(Op)) && TrackConstants) {
12671264
unsigned OpNo = Op.getOperandNo();

llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,12 @@ class SPIRVGlobalRegistry {
329329
return Ret;
330330
}
331331

332+
// Return true if the type is an aggregate type.
333+
bool isAggregateType(SPIRVType *Type) const {
334+
return Type && (Type->getOpcode() == SPIRV::OpTypeStruct &&
335+
Type->getOpcode() == SPIRV::OpTypeArray);
336+
}
337+
332338
// Whether the given VReg has an OpTypeXXX instruction mapped to it with the
333339
// given opcode (e.g. OpTypeFloat).
334340
bool isScalarOfType(Register VReg, unsigned TypeOpcode) const;

llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,20 +1445,50 @@ static unsigned getArrayComponentCount(MachineRegisterInfo *MRI,
14451445
}
14461446

14471447
// Return true if the type represents a constant register
1448-
static bool isConstReg(MachineRegisterInfo *MRI, SPIRVType *OpDef) {
1448+
static bool isConstReg(MachineRegisterInfo *MRI, SPIRVType *OpDef,
1449+
SmallPtrSet<SPIRVType *, 4> &Visited) {
14491450
if (OpDef->getOpcode() == SPIRV::ASSIGN_TYPE &&
14501451
OpDef->getOperand(1).isReg()) {
14511452
if (SPIRVType *RefDef = MRI->getVRegDef(OpDef->getOperand(1).getReg()))
14521453
OpDef = RefDef;
14531454
}
1454-
return OpDef->getOpcode() == TargetOpcode::G_CONSTANT ||
1455-
OpDef->getOpcode() == TargetOpcode::G_FCONSTANT;
1455+
1456+
if (Visited.contains(OpDef))
1457+
return true;
1458+
Visited.insert(OpDef);
1459+
1460+
unsigned Opcode = OpDef->getOpcode();
1461+
switch (Opcode) {
1462+
case TargetOpcode::G_CONSTANT:
1463+
case TargetOpcode::G_FCONSTANT:
1464+
return true;
1465+
case TargetOpcode::G_INTRINSIC:
1466+
case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
1467+
case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
1468+
return cast<GIntrinsic>(*OpDef).getIntrinsicID() ==
1469+
Intrinsic::spv_const_composite;
1470+
case TargetOpcode::G_BUILD_VECTOR:
1471+
case TargetOpcode::G_SPLAT_VECTOR: {
1472+
for (unsigned i = OpDef->getNumExplicitDefs(); i < OpDef->getNumOperands();
1473+
i++) {
1474+
SPIRVType *OpNestedDef =
1475+
OpDef->getOperand(i).isReg()
1476+
? MRI->getVRegDef(OpDef->getOperand(i).getReg())
1477+
: nullptr;
1478+
if (OpNestedDef && !isConstReg(MRI, OpNestedDef, Visited))
1479+
return false;
1480+
}
1481+
return true;
1482+
}
1483+
}
1484+
return false;
14561485
}
14571486

14581487
// Return true if the virtual register represents a constant
14591488
static bool isConstReg(MachineRegisterInfo *MRI, Register OpReg) {
1489+
SmallPtrSet<SPIRVType *, 4> Visited;
14601490
if (SPIRVType *OpDef = MRI->getVRegDef(OpReg))
1461-
return isConstReg(MRI, OpDef);
1491+
return isConstReg(MRI, OpDef, Visited);
14621492
return false;
14631493
}
14641494

@@ -1882,8 +1912,10 @@ bool SPIRVInstructionSelector::wrapIntoSpecConstantOp(
18821912
Register OpReg = I.getOperand(i).getReg();
18831913
SPIRVType *OpDefine = MRI->getVRegDef(OpReg);
18841914
SPIRVType *OpType = GR.getSPIRVTypeForVReg(OpReg);
1885-
if (!OpDefine || !OpType || isConstReg(MRI, OpDefine) ||
1886-
OpDefine->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST) {
1915+
SmallPtrSet<SPIRVType *, 4> Visited;
1916+
if (!OpDefine || !OpType || isConstReg(MRI, OpDefine, Visited) ||
1917+
OpDefine->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST ||
1918+
GR.isAggregateType(OpType)) {
18871919
// The case of G_ADDRSPACE_CAST inside spv_const_composite() is processed
18881920
// by selectAddrSpaceCast()
18891921
CompositeArgs.push_back(OpReg);
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
3+
4+
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
5+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
6+
7+
; CHECK-SPIRV: %[[#IntTy:]] = OpTypeInt 32 0
8+
; CHECK-SPIRV: %[[#Const16:]] = OpConstant %[[#IntTy]] 16
9+
; CHECK-SPIRV: %[[#ArrayTy:]] = OpTypeArray %[[#IntTy]] %[[#Const16]]
10+
; CHECK-SPIRV: %[[#StructTy:]] = OpTypeStruct %[[#ArrayTy]]
11+
; CHECK-SPIRV-COUNT-16: %[[#]] = OpConstant %[[#IntTy]] {{[0-9]+}}
12+
; CHECK-SPIRV: %[[#ConstArray:]] = OpConstantComposite %[[#ArrayTy]] %[[#]] %[[#]] %[[#]] %[[#]] %[[#]] %[[#]] %[[#]] %[[#]] %[[#]] %[[#]] %[[#]] %[[#]] %[[#]] %[[#]] %[[#]] %[[#]]
13+
; CHECK-SPIRV: %[[#]] = OpConstantComposite %[[#StructTy]] %[[#ConstArray]]
14+
15+
%struct_array_16i32 = type { [16 x i32] }
16+
17+
@G = private unnamed_addr addrspace(1) constant %struct_array_16i32 { [16 x i32] [i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15] }, align 4
18+
19+
define spir_kernel void @test() {
20+
ret void
21+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
3+
4+
; TODO: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefix=CHECK-SPIRV
5+
; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
6+
7+
; CHECK-SPIRV: OpName %[[#Var:]] "var"
8+
; CHECK-SPIRV: OpName %[[#GVar:]] "g_var"
9+
; CHECK-SPIRV: OpName %[[#AVar:]] "a_var"
10+
; CHECK-SPIRV: OpName %[[#PVar:]] "p_var"
11+
12+
; CHECK-SPIRV-DAG: %[[#CharTy:]] = OpTypeInt 8 0
13+
; CHECK-SPIRV-DAG: %[[#IntTy:]] = OpTypeInt 32 0
14+
; CHECK-SPIRV-DAG: %[[#V2CharTy:]] = OpTypeVector %[[#CharTy]] 2
15+
; CHECK-SPIRV-DAG: %[[#V2ConstNull:]] = OpConstantNull %[[#V2CharTy]]
16+
; CHECK-SPIRV-DAG: %[[#Const1:]] = OpConstant %[[#CharTy]] 1
17+
; CHECK-SPIRV-DAG: %[[#Const2:]] = OpConstant %[[#IntTy]] 2
18+
; CHECK-SPIRV-DAG: %[[#Arr2V2CharTy:]] = OpTypeArray %[[#V2CharTy]] %[[#Const2]]
19+
; CHECK-SPIRV-DAG: %[[#LongTy:]] = OpTypeInt 64 0
20+
; CHECK-SPIRV-DAG: %[[#PtrV2CharTy:]] = OpTypePointer CrossWorkgroup %[[#V2CharTy]]
21+
; CHECK-SPIRV-DAG: %[[#V2Char1:]] = OpConstantComposite %[[#V2CharTy]] %[[#Const1]] %[[#Const1]]
22+
; CHECK-SPIRV-DAG: %[[#Arr2V2Char:]] = OpConstantComposite %[[#Arr2V2CharTy]] %[[#V2Char1]] %[[#V2Char1]]
23+
; CHECK-SPIRV-DAG: %[[#PtrCharTy:]] = OpTypePointer CrossWorkgroup %[[#CharTy]]
24+
; CHECK-SPIRV-DAG: %[[#PtrArr2V2CharTy:]] = OpTypePointer CrossWorkgroup %[[#Arr2V2CharTy]]
25+
; CHECK-SPIRV-DAG: %[[#IntZero:]] = OpConstantNull %[[#IntTy]]
26+
; CHECK-SPIRV-DAG: %[[#LongZero:]] = OpConstantNull %[[#LongTy]]
27+
; CHECK-SPIRV-DAG: %[[#ConstLong2:]] = OpConstant %[[#LongTy]] 2
28+
; CHECK-SPIRV-DAG: %[[#PvarInit:]] = OpSpecConstantOp %[[#PtrCharTy]] 70 %[[#VarV2Char:]] %[[#IntZero]] %[[#ConstLong2]]
29+
; CHECK-SPIRV-DAG: %[[#PtrPtrCharTy:]] = OpTypePointer CrossWorkgroup %[[#PtrCharTy]]
30+
; CHECK-SPIRV-DAG: %[[#AVar]] = OpVariable %[[#PtrArr2V2CharTy]] CrossWorkgroup %[[#Arr2V2Char]]
31+
; CHECK-SPIRV-DAG: %[[#PVar]] = OpVariable %[[#PtrPtrCharTy]] CrossWorkgroup %[[#PvarInit]]
32+
; CHECK-SPIRV-DAG: %[[#GVar]] = OpVariable %[[#PtrV2CharTy]] CrossWorkgroup %[[#V2Char1]]
33+
; CHECK-SPIRV-DAG: %[[#]] = OpVariable %[[#PtrV2CharTy]] CrossWorkgroup %[[#V2ConstNull]]
34+
35+
; As an option: %[[#Const0:]] = OpConstant %[[#CharTy]] 0
36+
; %[[#V2CharZero:]] = OpConstantComposite %[[#V2CharTy]] %[[#Const0]] %[[#Const0]]
37+
; %[[#]] = OpVariable %[[#PtrV2CharTy]] CrossWorkgroup %[[#V2CharZero]]
38+
39+
@var = addrspace(1) global <2 x i8> zeroinitializer, align 2
40+
@g_var = addrspace(1) global <2 x i8> <i8 1, i8 1>, align 2
41+
@a_var = addrspace(1) global [2 x <2 x i8>] [<2 x i8> <i8 1, i8 1>, <2 x i8> <i8 1, i8 1>], align 2
42+
@p_var = addrspace(1) global ptr addrspace(1) getelementptr (i8, ptr addrspace(1) @a_var, i64 2), align 8
43+
44+
define spir_func <2 x i8> @from_buf(<2 x i8> %a) #0 {
45+
entry:
46+
ret <2 x i8> %a
47+
}
48+
49+
define spir_func <2 x i8> @to_buf(<2 x i8> %a) #0 {
50+
entry:
51+
ret <2 x i8> %a
52+
}
53+
54+
define spir_kernel void @writer(ptr addrspace(1) %src, i32 %idx) #0 !kernel_arg_addr_space !5 !kernel_arg_access_qual !6 !kernel_arg_type !7 !kernel_arg_type_qual !8 !kernel_arg_base_type !7 !spirv.ParameterDecorations !9 {
55+
entry:
56+
%arrayidx = getelementptr inbounds <2 x i8>, ptr addrspace(1) %src, i64 0
57+
%0 = load <2 x i8>, ptr addrspace(1) %arrayidx, align 2
58+
%call = call spir_func <2 x i8> @from_buf(<2 x i8> %0) #0
59+
store <2 x i8> %call, ptr addrspace(1) @var, align 2
60+
%arrayidx1 = getelementptr inbounds <2 x i8>, ptr addrspace(1) %src, i64 1
61+
%1 = load <2 x i8>, ptr addrspace(1) %arrayidx1, align 2
62+
%call2 = call spir_func <2 x i8> @from_buf(<2 x i8> %1) #0
63+
store <2 x i8> %call2, ptr addrspace(1) @g_var, align 2
64+
%arrayidx3 = getelementptr inbounds <2 x i8>, ptr addrspace(1) %src, i64 2
65+
%2 = load <2 x i8>, ptr addrspace(1) %arrayidx3, align 2
66+
%call4 = call spir_func <2 x i8> @from_buf(<2 x i8> %2) #0
67+
%3 = getelementptr inbounds [2 x <2 x i8>], ptr addrspace(1) @a_var, i64 0, i64 0
68+
store <2 x i8> %call4, ptr addrspace(1) %3, align 2
69+
%arrayidx5 = getelementptr inbounds <2 x i8>, ptr addrspace(1) %src, i64 3
70+
%4 = load <2 x i8>, ptr addrspace(1) %arrayidx5, align 2
71+
%call6 = call spir_func <2 x i8> @from_buf(<2 x i8> %4) #0
72+
%5 = getelementptr inbounds [2 x <2 x i8>], ptr addrspace(1) @a_var, i64 0, i64 1
73+
store <2 x i8> %call6, ptr addrspace(1) %5, align 2
74+
%idx.ext = zext i32 %idx to i64
75+
%add.ptr = getelementptr inbounds <2 x i8>, ptr addrspace(1) %3, i64 %idx.ext
76+
store ptr addrspace(1) %add.ptr, ptr addrspace(1) @p_var, align 8
77+
ret void
78+
}
79+
80+
define spir_kernel void @reader(ptr addrspace(1) %dest, <2 x i8> %ptr_write_val) #0 !kernel_arg_addr_space !5 !kernel_arg_access_qual !6 !kernel_arg_type !10 !kernel_arg_type_qual !8 !kernel_arg_base_type !10 !spirv.ParameterDecorations !9 {
81+
entry:
82+
%call = call spir_func <2 x i8> @from_buf(<2 x i8> %ptr_write_val) #0
83+
%0 = load ptr addrspace(1), ptr addrspace(1) @p_var, align 8
84+
store volatile <2 x i8> %call, ptr addrspace(1) %0, align 2
85+
%1 = load <2 x i8>, ptr addrspace(1) @var, align 2
86+
%call1 = call spir_func <2 x i8> @to_buf(<2 x i8> %1) #0
87+
%arrayidx = getelementptr inbounds <2 x i8>, ptr addrspace(1) %dest, i64 0
88+
store <2 x i8> %call1, ptr addrspace(1) %arrayidx, align 2
89+
%2 = load <2 x i8>, ptr addrspace(1) @g_var, align 2
90+
%call2 = call spir_func <2 x i8> @to_buf(<2 x i8> %2) #0
91+
%arrayidx3 = getelementptr inbounds <2 x i8>, ptr addrspace(1) %dest, i64 1
92+
store <2 x i8> %call2, ptr addrspace(1) %arrayidx3, align 2
93+
%3 = getelementptr inbounds [2 x <2 x i8>], ptr addrspace(1) @a_var, i64 0, i64 0
94+
%4 = load <2 x i8>, ptr addrspace(1) %3, align 2
95+
%call4 = call spir_func <2 x i8> @to_buf(<2 x i8> %4) #0
96+
%arrayidx5 = getelementptr inbounds <2 x i8>, ptr addrspace(1) %dest, i64 2
97+
store <2 x i8> %call4, ptr addrspace(1) %arrayidx5, align 2
98+
%5 = getelementptr inbounds [2 x <2 x i8>], ptr addrspace(1) @a_var, i64 0, i64 1
99+
%6 = load <2 x i8>, ptr addrspace(1) %5, align 2
100+
%call6 = call spir_func <2 x i8> @to_buf(<2 x i8> %6) #0
101+
%arrayidx7 = getelementptr inbounds <2 x i8>, ptr addrspace(1) %dest, i64 3
102+
store <2 x i8> %call6, ptr addrspace(1) %arrayidx7, align 2
103+
ret void
104+
}
105+
106+
attributes #0 = { nounwind }
107+
108+
!spirv.MemoryModel = !{!0}
109+
!opencl.enable.FP_CONTRACT = !{}
110+
!spirv.Source = !{!1}
111+
!opencl.spir.version = !{!2}
112+
!opencl.ocl.version = !{!2}
113+
!opencl.used.extensions = !{!3}
114+
!opencl.used.optional.core.features = !{!3}
115+
!spirv.Generator = !{!4}
116+
117+
!0 = !{i32 2, i32 2}
118+
!1 = !{i32 3, i32 200000}
119+
!2 = !{i32 2, i32 0}
120+
!3 = !{}
121+
!4 = !{i16 6, i16 14}
122+
!5 = !{i32 1, i32 0}
123+
!6 = !{!"none", !"none"}
124+
!7 = !{!"char2*", !"int"}
125+
!8 = !{!"", !""}
126+
!9 = !{!3, !3}
127+
!10 = !{!"char2*", !"char2"}

llvm/test/CodeGen/SPIRV/opencl/image.ll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1+
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
3+
14
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
5+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
26

37
;; FIXME: Write tests to ensure invalid usage of image are rejected, such as:
48
;; - invalid AS (only global is allowed);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %}
3+
4+
; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s
5+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
6+
7+
; CHECK: OpName %[[#Var:]] "var"
8+
; CHECK-DAG: %[[#Char:]] = OpTypeInt 8 0
9+
; CHECK-DAG: %[[#Vec2Char:]] = OpTypeVector %[[#Char]] 2
10+
; CHECK-DAG: %[[#PtrVec2Char:]] = OpTypePointer CrossWorkgroup %[[#Vec2Char]]
11+
; CHECK-DAG: %[[#ConstNull:]] = OpConstantNull %[[#Vec2Char]]
12+
; CHECK: %[[#]] = OpVariable %[[#PtrVec2Char]] CrossWorkgroup %[[#ConstNull]]
13+
; As an option: %[[#C0:]] = OpConstant %[[#Char]] 0
14+
; %[[#VecZero:]] = OpConstantComposite %[[#Vec2Char]] %[[#C0]] %[[#C0]]
15+
; %[[#]] = OpVariable %[[#PtrVec2Char]] CrossWorkgroup %[[#VecZero]]
16+
; CHECK: OpFunction
17+
18+
@var = addrspace(1) global <2 x i8> zeroinitializer
19+
;@var = addrspace(1) global <2 x i8> <i8 1, i8 1>
20+
21+
define spir_kernel void @foo() {
22+
entry:
23+
%addr = load <2 x i8>, ptr addrspace(1) @var, align 2
24+
ret void
25+
}

0 commit comments

Comments
 (0)