21
21
22
22
using namespace llvm ;
23
23
24
- static void replaceTypedBufferAccess (IntrinsicInst *II,
25
- dxil::ResourceTypeInfo &RTI) {
26
- const DataLayout &DL = II->getDataLayout ();
24
+ static Value *calculateGEPOffset (GetElementPtrInst *GEP, Value *PrevOffset,
25
+ dxil::ResourceTypeInfo &RTI) {
26
+ assert (!PrevOffset && " Non-constant GEP chains not handled yet" );
27
+
28
+ const DataLayout &DL = GEP->getDataLayout ();
29
+
30
+ uint64_t ScalarSize = 1 ;
31
+ if (RTI.isTyped ()) {
32
+ Type *ContainedType = RTI.getHandleTy ()->getTypeParameter (0 );
33
+ // We need the size of an element in bytes so that we can calculate the
34
+ // offset in elements given a total offset in bytes.
35
+ Type *ScalarType = ContainedType->getScalarType ();
36
+ ScalarSize = DL.getTypeSizeInBits (ScalarType) / 8 ;
37
+ }
38
+
39
+ APInt ConstantOffset (DL.getIndexTypeSizeInBits (GEP->getType ()), 0 );
40
+ if (GEP->accumulateConstantOffset (DL, ConstantOffset)) {
41
+ APInt Scaled = ConstantOffset.udiv (ScalarSize);
42
+ return ConstantInt::get (Type::getInt32Ty (GEP->getContext ()), Scaled);
43
+ }
44
+
45
+ auto IndexIt = GEP->idx_begin ();
46
+ assert (cast<ConstantInt>(IndexIt)->getZExtValue () == 0 &&
47
+ " GEP is not indexing through pointer" );
48
+ ++IndexIt;
49
+ Value *Offset = *IndexIt;
50
+ assert (++IndexIt == GEP->idx_end () && " Too many indices in GEP" );
51
+ return Offset;
52
+ }
53
+
54
+ static void createTypedBufferStore (IntrinsicInst *II, StoreInst *SI,
55
+ Value *Offset, dxil::ResourceTypeInfo &RTI) {
56
+ IRBuilder<> Builder (SI);
57
+ Type *ContainedType = RTI.getHandleTy ()->getTypeParameter (0 );
58
+ Type *LoadType = StructType::get (ContainedType, Builder.getInt1Ty ());
59
+
60
+ Value *V = SI->getValueOperand ();
61
+ if (V->getType () == ContainedType) {
62
+ // V is already the right type.
63
+ assert (!Offset && " store of whole element has offset?" );
64
+ } else if (V->getType () == ContainedType->getScalarType ()) {
65
+ // We're storing a scalar, so we need to load the current value and only
66
+ // replace the relevant part.
67
+ auto *Load = Builder.CreateIntrinsic (
68
+ LoadType, Intrinsic::dx_resource_load_typedbuffer,
69
+ {II->getOperand (0 ), II->getOperand (1 )});
70
+ auto *Struct = Builder.CreateExtractValue (Load, {0 });
71
+
72
+ // If we have an offset from seeing a GEP earlier, use that. Otherwise, 0.
73
+ if (!Offset)
74
+ Offset = ConstantInt::get (Builder.getInt32Ty (), 0 );
75
+ V = Builder.CreateInsertElement (Struct, V, Offset);
76
+ } else {
77
+ llvm_unreachable (" Store to typed resource has invalid type" );
78
+ }
79
+
80
+ auto *Inst = Builder.CreateIntrinsic (
81
+ Builder.getVoidTy (), Intrinsic::dx_resource_store_typedbuffer,
82
+ {II->getOperand (0 ), II->getOperand (1 ), V});
83
+ SI->replaceAllUsesWith (Inst);
84
+ }
85
+
86
+ static void createRawStore (IntrinsicInst *II, StoreInst *SI, Value *Offset) {
87
+ IRBuilder<> Builder (SI);
88
+
89
+ if (!Offset)
90
+ Offset = ConstantInt::get (Builder.getInt32Ty (), 0 );
91
+ Value *V = SI->getValueOperand ();
92
+ // TODO: break up larger types
93
+ auto *Inst = Builder.CreateIntrinsic (
94
+ Builder.getVoidTy (), Intrinsic::dx_resource_store_rawbuffer,
95
+ {II->getOperand (0 ), II->getOperand (1 ), Offset, V});
96
+ SI->replaceAllUsesWith (Inst);
97
+ }
98
+
99
+ static void createStoreIntrinsic (IntrinsicInst *II, StoreInst *SI,
100
+ Value *Offset, dxil::ResourceTypeInfo &RTI) {
101
+ switch (RTI.getResourceKind ()) {
102
+ case dxil::ResourceKind::TypedBuffer:
103
+ return createTypedBufferStore (II, SI, Offset, RTI);
104
+ case dxil::ResourceKind::RawBuffer:
105
+ case dxil::ResourceKind::StructuredBuffer:
106
+ return createRawStore (II, SI, Offset);
107
+ case dxil::ResourceKind::Texture1D:
108
+ case dxil::ResourceKind::Texture2D:
109
+ case dxil::ResourceKind::Texture2DMS:
110
+ case dxil::ResourceKind::Texture3D:
111
+ case dxil::ResourceKind::TextureCube:
112
+ case dxil::ResourceKind::Texture1DArray:
113
+ case dxil::ResourceKind::Texture2DArray:
114
+ case dxil::ResourceKind::Texture2DMSArray:
115
+ case dxil::ResourceKind::TextureCubeArray:
116
+ case dxil::ResourceKind::FeedbackTexture2D:
117
+ case dxil::ResourceKind::FeedbackTexture2DArray:
118
+ report_fatal_error (" DXIL Load not implemented yet" ,
119
+ /* gen_crash_diag=*/ false );
120
+ return ;
121
+ case dxil::ResourceKind::CBuffer:
122
+ case dxil::ResourceKind::Sampler:
123
+ case dxil::ResourceKind::TBuffer:
124
+ case dxil::ResourceKind::RTAccelerationStructure:
125
+ case dxil::ResourceKind::Invalid:
126
+ case dxil::ResourceKind::NumEntries:
127
+ llvm_unreachable (" Invalid resource kind for store" );
128
+ }
129
+ llvm_unreachable (" Unhandled case in switch" );
130
+ }
131
+
132
+ static void createTypedBufferLoad (IntrinsicInst *II, LoadInst *LI,
133
+ Value *Offset, dxil::ResourceTypeInfo &RTI) {
134
+ IRBuilder<> Builder (LI);
135
+ Type *ContainedType = RTI.getHandleTy ()->getTypeParameter (0 );
136
+ Type *LoadType = StructType::get (ContainedType, Builder.getInt1Ty ());
27
137
28
- auto *HandleType = cast<TargetExtType>(II-> getOperand ( 0 )-> getType ());
29
- assert (HandleType-> getName () == " dx.TypedBuffer " &&
30
- " Unexpected typed buffer type " );
31
- Type *ContainedType = HandleType-> getTypeParameter ( 0 );
138
+ Value *V =
139
+ Builder. CreateIntrinsic (LoadType, Intrinsic::dx_resource_load_typedbuffer,
140
+ {II-> getOperand ( 0 ), II-> getOperand ( 1 )} );
141
+ V = Builder. CreateExtractValue (V, { 0 } );
32
142
33
- Type *LoadType =
34
- StructType::get (ContainedType, Type::getInt1Ty (II-> getContext ()) );
143
+ if (Offset)
144
+ V = Builder. CreateExtractElement (V, Offset );
35
145
36
- // We need the size of an element in bytes so that we can calculate the offset
37
- // in elements given a total offset in bytes later.
38
- Type *ScalarType = ContainedType->getScalarType ();
39
- uint64_t ScalarSize = DL.getTypeSizeInBits (ScalarType) / 8 ;
146
+ LI->replaceAllUsesWith (V);
147
+ }
40
148
149
+ static void createRawLoad (IntrinsicInst *II, LoadInst *LI, Value *Offset) {
150
+ IRBuilder<> Builder (LI);
151
+ // TODO: break up larger types
152
+ Type *LoadType = StructType::get (LI->getType (), Builder.getInt1Ty ());
153
+ if (!Offset)
154
+ Offset = ConstantInt::get (Builder.getInt32Ty (), 0 );
155
+ Value *V =
156
+ Builder.CreateIntrinsic (LoadType, Intrinsic::dx_resource_load_rawbuffer,
157
+ {II->getOperand (0 ), II->getOperand (1 ), Offset});
158
+ V = Builder.CreateExtractValue (V, {0 });
159
+
160
+ LI->replaceAllUsesWith (V);
161
+ }
162
+
163
+ static void createLoadIntrinsic (IntrinsicInst *II, LoadInst *LI, Value *Offset,
164
+ dxil::ResourceTypeInfo &RTI) {
165
+ switch (RTI.getResourceKind ()) {
166
+ case dxil::ResourceKind::TypedBuffer:
167
+ return createTypedBufferLoad (II, LI, Offset, RTI);
168
+ case dxil::ResourceKind::RawBuffer:
169
+ case dxil::ResourceKind::StructuredBuffer:
170
+ return createRawLoad (II, LI, Offset);
171
+ case dxil::ResourceKind::Texture1D:
172
+ case dxil::ResourceKind::Texture2D:
173
+ case dxil::ResourceKind::Texture2DMS:
174
+ case dxil::ResourceKind::Texture3D:
175
+ case dxil::ResourceKind::TextureCube:
176
+ case dxil::ResourceKind::Texture1DArray:
177
+ case dxil::ResourceKind::Texture2DArray:
178
+ case dxil::ResourceKind::Texture2DMSArray:
179
+ case dxil::ResourceKind::TextureCubeArray:
180
+ case dxil::ResourceKind::FeedbackTexture2D:
181
+ case dxil::ResourceKind::FeedbackTexture2DArray:
182
+ case dxil::ResourceKind::CBuffer:
183
+ case dxil::ResourceKind::TBuffer:
184
+ // TODO: handle these
185
+ return ;
186
+ case dxil::ResourceKind::Sampler:
187
+ case dxil::ResourceKind::RTAccelerationStructure:
188
+ case dxil::ResourceKind::Invalid:
189
+ case dxil::ResourceKind::NumEntries:
190
+ llvm_unreachable (" Invalid resource kind for load" );
191
+ }
192
+ llvm_unreachable (" Unhandled case in switch" );
193
+ }
194
+
195
+ static void replaceAccess (IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) {
41
196
// Process users keeping track of indexing accumulated from GEPs.
42
- struct AccessAndIndex {
197
+ struct AccessAndOffset {
43
198
User *Access;
44
- Value *Index ;
199
+ Value *Offset ;
45
200
};
46
- SmallVector<AccessAndIndex > Worklist;
201
+ SmallVector<AccessAndOffset > Worklist;
47
202
for (User *U : II->users ())
48
203
Worklist.push_back ({U, nullptr });
49
204
50
205
SmallVector<Instruction *> DeadInsts;
51
206
while (!Worklist.empty ()) {
52
- AccessAndIndex Current = Worklist.back ();
207
+ AccessAndOffset Current = Worklist.back ();
53
208
Worklist.pop_back ();
54
209
55
210
if (auto *GEP = dyn_cast<GetElementPtrInst>(Current.Access )) {
56
211
IRBuilder<> Builder (GEP);
57
212
58
- Value *Index;
59
- APInt ConstantOffset (DL.getIndexTypeSizeInBits (GEP->getType ()), 0 );
60
- if (GEP->accumulateConstantOffset (DL, ConstantOffset)) {
61
- APInt Scaled = ConstantOffset.udiv (ScalarSize);
62
- Index = ConstantInt::get (Builder.getInt32Ty (), Scaled);
63
- } else {
64
- auto IndexIt = GEP->idx_begin ();
65
- assert (cast<ConstantInt>(IndexIt)->getZExtValue () == 0 &&
66
- " GEP is not indexing through pointer" );
67
- ++IndexIt;
68
- Index = *IndexIt;
69
- assert (++IndexIt == GEP->idx_end () && " Too many indices in GEP" );
70
- }
71
-
213
+ Value *Offset = calculateGEPOffset (GEP, Current.Offset , RTI);
72
214
for (User *U : GEP->users ())
73
- Worklist.push_back ({U, Index });
215
+ Worklist.push_back ({U, Offset });
74
216
DeadInsts.push_back (GEP);
75
217
76
218
} else if (auto *SI = dyn_cast<StoreInst>(Current.Access )) {
77
219
assert (SI->getValueOperand () != II && " Pointer escaped!" );
78
- IRBuilder<> Builder (SI);
79
-
80
- Value *V = SI->getValueOperand ();
81
- if (V->getType () == ContainedType) {
82
- // V is already the right type.
83
- } else if (V->getType () == ScalarType) {
84
- // We're storing a scalar, so we need to load the current value and only
85
- // replace the relevant part.
86
- auto *Load = Builder.CreateIntrinsic (
87
- LoadType, Intrinsic::dx_resource_load_typedbuffer,
88
- {II->getOperand (0 ), II->getOperand (1 )});
89
- auto *Struct = Builder.CreateExtractValue (Load, {0 });
90
-
91
- // If we have an offset from seeing a GEP earlier, use it.
92
- Value *IndexOp = Current.Index
93
- ? Current.Index
94
- : ConstantInt::get (Builder.getInt32Ty (), 0 );
95
- V = Builder.CreateInsertElement (Struct, V, IndexOp);
96
- } else {
97
- llvm_unreachable (" Store to typed resource has invalid type" );
98
- }
99
-
100
- auto *Inst = Builder.CreateIntrinsic (
101
- Builder.getVoidTy (), Intrinsic::dx_resource_store_typedbuffer,
102
- {II->getOperand (0 ), II->getOperand (1 ), V});
103
- SI->replaceAllUsesWith (Inst);
220
+ createStoreIntrinsic (II, SI, Current.Offset , RTI);
104
221
DeadInsts.push_back (SI);
105
222
106
223
} else if (auto *LI = dyn_cast<LoadInst>(Current.Access )) {
107
- IRBuilder<> Builder (LI);
108
- Value *V = Builder.CreateIntrinsic (
109
- LoadType, Intrinsic::dx_resource_load_typedbuffer,
110
- {II->getOperand (0 ), II->getOperand (1 )});
111
- V = Builder.CreateExtractValue (V, {0 });
112
-
113
- if (Current.Index )
114
- V = Builder.CreateExtractElement (V, Current.Index );
115
-
116
- LI->replaceAllUsesWith (V);
224
+ createLoadIntrinsic (II, LI, Current.Offset , RTI);
117
225
DeadInsts.push_back (LI);
118
226
119
227
} else
@@ -137,15 +245,8 @@ static bool transformResourcePointers(Function &F, DXILResourceTypeMap &DRTM) {
137
245
Resources.emplace_back (II, DRTM[HandleTy]);
138
246
}
139
247
140
- for (auto &[II, RI] : Resources) {
141
- if (RI.isTyped ()) {
142
- Changed = true ;
143
- replaceTypedBufferAccess (II, RI);
144
- }
145
-
146
- // TODO: handle other resource types. We should probably have an
147
- // `unreachable` here once we've added support for all of them.
148
- }
248
+ for (auto &[II, RI] : Resources)
249
+ replaceAccess (II, RI);
149
250
150
251
return Changed;
151
252
}
0 commit comments