88
99#include " DXILCBufferAccess.h"
1010#include " DirectX.h"
11+ #include " llvm/Analysis/DXILResource.h"
1112#include " llvm/Frontend/HLSL/CBuffer.h"
1213#include " llvm/Frontend/HLSL/HLSLResource.h"
1314#include " llvm/IR/IRBuilder.h"
@@ -97,10 +98,6 @@ struct CBufferResource {
9798 (void )Success;
9899 assert (Success && " Offsets into cbuffer globals must be constant" );
99100
100- if (auto *ATy = dyn_cast<ArrayType>(Member->getValueType ()))
101- ConstantOffset =
102- hlsl::translateCBufArrayOffset (DL, ConstantOffset, ATy);
103-
104101 return ConstantOffset.getZExtValue ();
105102 }
106103
@@ -194,102 +191,21 @@ static void replaceLoad(LoadInst *LI, CBufferResource &CBR,
194191 DeadInsts.push_back (LI);
195192}
196193
197- // / This function recursively copies N array elements from the cbuffer resource
198- // / CBR to the MemCpy Destination. Recursion is used to unravel multidimensional
199- // / arrays into a sequence of scalar/vector extracts and stores.
200- static void copyArrayElemsForMemCpy (IRBuilder<> &Builder, MemCpyInst *MCI,
201- CBufferResource &CBR, ArrayType *ArrTy,
202- size_t ArrOffset, size_t N,
203- const Twine &Name = " " ) {
204- const DataLayout &DL = MCI->getDataLayout ();
205- Type *ElemTy = ArrTy->getElementType ();
206- size_t ElemTySize = DL.getTypeAllocSize (ElemTy);
207- for (unsigned I = 0 ; I < N; ++I) {
208- size_t Offset = ArrOffset + I * ElemTySize;
209-
210- // Recursively copy nested arrays
211- if (ArrayType *ElemArrTy = dyn_cast<ArrayType>(ElemTy)) {
212- copyArrayElemsForMemCpy (Builder, MCI, CBR, ElemArrTy, Offset,
213- ElemArrTy->getNumElements (), Name);
214- continue ;
215- }
216-
217- // Load CBuffer value and store it in Dest
218- APInt CBufArrayOffset (
219- DL.getIndexTypeSizeInBits (MCI->getSource ()->getType ()), Offset);
220- CBufArrayOffset =
221- hlsl::translateCBufArrayOffset (DL, CBufArrayOffset, ArrTy);
222- Value *CBufferVal =
223- CBR.loadValue (Builder, ElemTy, CBufArrayOffset.getZExtValue (), Name);
224- Value *GEP =
225- Builder.CreateInBoundsGEP (Builder.getInt8Ty (), MCI->getDest (),
226- {Builder.getInt32 (Offset)}, Name + " .dest" );
227- Builder.CreateStore (CBufferVal, GEP, MCI->isVolatile ());
228- }
229- }
230-
231- // / Replace memcpy from a cbuffer global with a memcpy from the cbuffer handle
232- // / itself. Assumes the cbuffer global is an array, and the length of bytes to
233- // / copy is divisible by array element allocation size.
234- // / The memcpy source must also be a direct cbuffer global reference, not a GEP.
235- static void replaceMemCpy (MemCpyInst *MCI, CBufferResource &CBR) {
236-
237- ArrayType *ArrTy = dyn_cast<ArrayType>(CBR.getValueType ());
238- assert (ArrTy && " MemCpy lowering is only supported for array types" );
239-
240- // This assumption vastly simplifies the implementation
241- if (MCI->getSource () != CBR.Member )
242- reportFatalUsageError (
243- " Expected MemCpy source to be a cbuffer global variable" );
244-
245- ConstantInt *Length = dyn_cast<ConstantInt>(MCI->getLength ());
246- uint64_t ByteLength = Length->getZExtValue ();
247-
248- // If length to copy is zero, no memcpy is needed
249- if (ByteLength == 0 ) {
250- MCI->eraseFromParent ();
251- return ;
252- }
253-
254- const DataLayout &DL = CBR.getDataLayout ();
255-
256- Type *ElemTy = ArrTy->getElementType ();
257- size_t ElemSize = DL.getTypeAllocSize (ElemTy);
258- assert (ByteLength % ElemSize == 0 &&
259- " Length of bytes to MemCpy must be divisible by allocation size of "
260- " source/destination array elements" );
261- size_t ElemsToCpy = ByteLength / ElemSize;
262-
263- IRBuilder<> Builder (MCI);
264- CBR.createAndSetCurrentHandle (Builder);
265-
266- copyArrayElemsForMemCpy (Builder, MCI, CBR, ArrTy, 0 , ElemsToCpy,
267- " memcpy." + MCI->getDest ()->getName () + " ." +
268- MCI->getSource ()->getName ());
269-
270- MCI->eraseFromParent ();
271- }
272-
273194static void replaceAccessesWithHandle (CBufferResource &CBR) {
274195 SmallVector<WeakTrackingVH> DeadInsts;
275196
276197 SmallVector<User *> ToProcess{CBR.users ()};
277198 while (!ToProcess.empty ()) {
278199 User *Cur = ToProcess.pop_back_val ();
200+ assert (!isa<MemCpyInst>(Cur) &&
201+ " memcpy should have been removed in an earlier pass" );
279202
280203 // If we have a load instruction, replace the access.
281204 if (auto *LI = dyn_cast<LoadInst>(Cur)) {
282205 replaceLoad (LI, CBR, DeadInsts);
283206 continue ;
284207 }
285208
286- // If we have a memcpy instruction, replace it with multiple accesses and
287- // subsequent stores to the destination
288- if (auto *MCI = dyn_cast<MemCpyInst>(Cur)) {
289- replaceMemCpy (MCI, CBR);
290- continue ;
291- }
292-
293209 // Otherwise, walk users looking for a load...
294210 if (isa<GetElementPtrInst>(Cur) || isa<GEPOperator>(Cur)) {
295211 ToProcess.append (Cur->user_begin (), Cur->user_end ());
@@ -302,7 +218,8 @@ static void replaceAccessesWithHandle(CBufferResource &CBR) {
302218}
303219
304220static bool replaceCBufferAccesses (Module &M) {
305- std::optional<hlsl::CBufferMetadata> CBufMD = hlsl::CBufferMetadata::get (M);
221+ std::optional<hlsl::CBufferMetadata> CBufMD = hlsl::CBufferMetadata::get (
222+ M, [](Type *Ty) { return isa<llvm::dxil::PaddingExtType>(Ty); });
306223 if (!CBufMD)
307224 return false ;
308225
0 commit comments