LLVM: lib/Target/DirectX/DXILResourceAccess.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

21#include "llvm/IR/IntrinsicsDirectX.h"

26

27#define DEBUG_TYPE "dxil-resource-access"

28

29using namespace llvm;

30

33 assert(!PrevOffset && "Non-constant GEP chains not handled yet");

34

36

40

41

43 ScalarSize = DL.getTypeSizeInBits(ScalarType) / 8;

44 }

45

46 APInt ConstantOffset(DL.getIndexTypeSizeInBits(GEP->getType()), 0);

47 if (GEP->accumulateConstantOffset(DL, ConstantOffset)) {

49 return ConstantInt::get(DL.getIndexType(GEP->getType()), Scaled);

50 }

51

52 unsigned NumIndices = GEP->getNumIndices();

53

54

55

56 if (NumIndices == 1)

57 return *GEP->idx_begin();

58

59

60 if (NumIndices == 2) {

61 auto IndexIt = GEP->idx_begin();

63 "GEP is not indexing through pointer");

64 ++IndexIt;

66 assert(++IndexIt == GEP->idx_end() && "Too many indices in GEP");

68 }

69

70 llvm_unreachable("Unhandled GEP structure for resource access");

71}

72

78

79 Value *V = SI->getValueOperand();

80 if (V->getType() == ContainedType) {

81

82 assert(Offset && "store of whole element has offset?");

83 } else if (V->getType() == ContainedType->getScalarType()) {

84

85

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

93 Offset = ConstantInt::get(Builder.getInt32Ty(), 0);

94 V = Builder.CreateInsertElement(Struct, V, Offset);

95 } else {

97 }

98

99 auto *Inst = Builder.CreateIntrinsic(

100 Builder.getVoidTy(), Intrinsic::dx_resource_store_typedbuffer,

101 {II->getOperand(0), II->getOperand(1), V});

102 SI->replaceAllUsesWith(Inst);

103}

104

107

109 Offset = ConstantInt::get(Builder.getInt32Ty(), 0);

110 Value *V = SI->getValueOperand();

111

112 auto *Inst = Builder.CreateIntrinsic(

113 Builder.getVoidTy(), Intrinsic::dx_resource_store_rawbuffer,

114 {II->getOperand(0), II->getOperand(1), Offset, V});

115 SI->replaceAllUsesWith(Inst);

116}

117

149

155

157 Builder.CreateIntrinsic(LoadType, Intrinsic::dx_resource_load_typedbuffer,

158 {II->getOperand(0), II->getOperand(1)});

159 V = Builder.CreateExtractValue(V, {0});

160

162 V = Builder.CreateExtractElement(V, Offset);

163

164

165

169 Builder.getInt32(0));

170

172}

173

176

179 Offset = ConstantInt::get(Builder.getInt32Ty(), 0);

181 Builder.CreateIntrinsic(LoadType, Intrinsic::dx_resource_load_rawbuffer,

182 {II->getOperand(0), II->getOperand(1), Offset});

183 V = Builder.CreateExtractValue(V, {0});

184

186}

187

188namespace {

189

190struct CBufferRowIntrin {

193 unsigned int EltSize;

194 unsigned int NumElts;

195

196 CBufferRowIntrin(const DataLayout &DL, Type *Ty) {

198

199 switch (DL.getTypeSizeInBits(Ty)) {

200 case 16:

201 IID = Intrinsic::dx_resource_load_cbufferrow_8;

203 EltSize = 2;

204 NumElts = 8;

205 break;

206 case 32:

207 IID = Intrinsic::dx_resource_load_cbufferrow_4;

209 EltSize = 4;

210 NumElts = 4;

211 break;

212 case 64:

213 IID = Intrinsic::dx_resource_load_cbufferrow_2;

215 EltSize = 8;

216 NumElts = 2;

217 break;

218 default:

220 }

221 }

222};

223}

224

228

231 CBufferRowIntrin Intrin(DL, Ty->getScalarType());

232

234 Value *Handle = II->getOperand(0);

235

237

239 assert(GlobalOffset && "CBuffer getpointer index must be constant");

240

241 unsigned int FixedOffset = GlobalOffset->getZExtValue();

242

243

245 FixedOffset += ConstOffset->getZExtValue();

247 }

248

249 Value *CurrentRow = ConstantInt::get(

251 unsigned int CurrentIndex =

253

255 "Dynamic indexing into elements of cbuffer rows is not supported");

256

257

259 CurrentRow = FixedOffset ? Builder.CreateAdd(CurrentRow, Offset) : Offset;

260

261 auto *CBufLoad = Builder.CreateIntrinsic(

262 Intrin.RetTy, Intrin.IID, {Handle, CurrentRow}, nullptr, Name + ".load");

263 auto *Elt =

264 Builder.CreateExtractValue(CBufLoad, {CurrentIndex++}, Name + ".extract");

265

266

267

268 unsigned int Remaining =

269 ((DL.getTypeSizeInBits(Ty) / 8) / Intrin.EltSize) - 1;

270 if (Remaining == 0) {

271

272 Value *Result = Elt;

273

274

276 assert(VT->getNumElements() == 1 && "Can't have multiple elements here");

277 Result = Builder.CreateInsertElement(PoisonValue::get(VT), Result,

278 Builder.getInt32(0), Name);

279 }

281 return;

282 }

283

284

286 while (Remaining--) {

287 CurrentIndex %= Intrin.NumElts;

288

289 if (CurrentIndex == 0) {

290 CurrentRow = Builder.CreateAdd(CurrentRow,

291 ConstantInt::get(Builder.getInt32Ty(), 1));

292 CBufLoad = Builder.CreateIntrinsic(Intrin.RetTy, Intrin.IID,

293 {Handle, CurrentRow}, nullptr,

294 Name + ".load");

295 }

296

297 Extracts.push_back(Builder.CreateExtractValue(CBufLoad, {CurrentIndex++},

298 Name + ".extract"));

299 }

300

301

303 for (int I = 0, E = Extracts.size(); I < E; ++I)

304 Result = Builder.CreateInsertElement(

305 Result, Extracts[I], Builder.getInt32(I), Name + formatv(".upto{}", I));

307}

308

341

346 auto *BB = Start->getParent();

347

348

349 for (User *U : Start->users()) {

351 if (I->getParent() == BB)

353 }

354 }

355

356

357 while (!Worklist.empty()) {

359 if (!Visited.insert(I).second)

360 continue;

362

363 for (User *U : I->users()) {

365 if (J->getParent() == BB)

367 }

368 }

369 for (Use &V : I->operands()) {

371 if (J->getParent() == BB && V != Start)

373 }

374 }

375 }

376

377

379 unsigned Idx = 0;

381 Ord[&I] = Idx++;

382

385 });

386

387 return Out;

388}

389

393

395 Value *Val = Phi->getIncomingValueForBlock(BB);

396 VMap[Phi] = Val;

397 Builder.SetInsertPoint(&BB->back());

399

401 VMap[PhiNested] = PhiNested->getIncomingValueForBlock(BB);

402 continue;

403 }

407 Builder.Insert(Clone);

408 VMap[I] = Clone;

409 }

410}

411

416 for (User *U : II->users()) {

418 if (!Phi)

419 continue;

420

424

425 for (unsigned I = 0, E = Phi->getNumIncomingValues(); I < E; I++) {

426 auto *CurrIncomingBB = Phi->getIncomingBlock(I);

428 if (HasReturnUse)

429 PrevBBDeadInsts.push_back(&CurrIncomingBB->back());

430 }

431

433

436 }

437 if (HasReturnUse) {

438 BasicBlock *PhiBB = Phi->getParent();

439 DeadBB.insert(PhiBB);

440 }

441 }

442

444 Dead->eraseFromParent();

445 CurrBBDeadInsts.clear();

446}

447

449

450 struct AccessAndOffset {

453 };

455 for (User *U : II->users())

456 Worklist.push_back({U, nullptr});

457

459 while (!Worklist.empty()) {

460 AccessAndOffset Current = Worklist.back();

462

465

467 for (User *U : GEP->users())

470

472 assert(SI->getValueOperand() != II && "Pointer escaped!");

475

479 } else

480 llvm_unreachable("Unhandled instruction - pointer escaped?");

481 }

482

483

485 Dead->eraseFromParent();

486 II->eraseFromParent();

487}

488

496 if (II->getIntrinsicID() == Intrinsic::dx_resource_getpointer)

498

501 if (II->getIntrinsicID() == Intrinsic::dx_resource_getpointer) {

504 }

505 }

506 for (auto *Dead : PrevBBDeadInsts)

507 Dead->eraseFromParent();

508 PrevBBDeadInsts.clear();

509 for (auto *Dead : DeadBB)

510 Dead->eraseFromParent();

512

513 for (auto &[II, RI] : Resources)

515

516 return !Resources.empty();

517}

518

524 assert(DRTM && "DXILResourceTypeAnalysis must be available");

525

527 if (!MadeChanges)

529

533 return PA;

534}

535

536namespace {

537class DXILResourceAccessLegacy : public FunctionPass {

538public:

541 getAnalysis().getResourceTypeMap();

543 }

544 StringRef getPassName() const override { return "DXIL Resource Access"; }

545 DXILResourceAccessLegacy() : FunctionPass(ID) {}

546

547 static char ID;

548 void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {

549 AU.addRequired();

551 }

552};

553char DXILResourceAccessLegacy::ID = 0;

554}

555

557 "DXIL Resource Access", false, false)

561

563 return new DXILResourceAccessLegacy();

564}

assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")

static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

static void phiNodeRemapHelper(PHINode *Phi, BasicBlock *BB, IRBuilder<> &Builder, SmallVector< Instruction * > &UsesInBlock)

Definition DXILResourceAccess.cpp:390

static Value * calculateGEPOffset(GetElementPtrInst *GEP, Value *PrevOffset, dxil::ResourceTypeInfo &RTI)

Definition DXILResourceAccess.cpp:31

static bool transformResourcePointers(Function &F, DXILResourceTypeMap &DRTM)

Definition DXILResourceAccess.cpp:489

static void createRawLoad(IntrinsicInst *II, LoadInst *LI, Value *Offset)

Definition DXILResourceAccess.cpp:174

static void createLoadIntrinsic(IntrinsicInst *II, LoadInst *LI, Value *Offset, dxil::ResourceTypeInfo &RTI)

Definition DXILResourceAccess.cpp:309

static void createTypedBufferLoad(IntrinsicInst *II, LoadInst *LI, Value *Offset, dxil::ResourceTypeInfo &RTI)

Definition DXILResourceAccess.cpp:150

static void createStoreIntrinsic(IntrinsicInst *II, StoreInst *SI, Value *Offset, dxil::ResourceTypeInfo &RTI)

Definition DXILResourceAccess.cpp:118

static void createCBufferLoad(IntrinsicInst *II, LoadInst *LI, Value *Offset, dxil::ResourceTypeInfo &RTI)

Definition DXILResourceAccess.cpp:225

static void createTypedBufferStore(IntrinsicInst *II, StoreInst *SI, Value *Offset, dxil::ResourceTypeInfo &RTI)

Definition DXILResourceAccess.cpp:73

static SmallVector< Instruction * > collectBlockUseDef(Instruction *Start)

Definition DXILResourceAccess.cpp:342

DXIL Resource Access

Definition DXILResourceAccess.cpp:560

static void phiNodeReplacement(IntrinsicInst *II, SmallVectorImpl< Instruction * > &PrevBBDeadInsts, SetVector< BasicBlock * > &DeadBB)

Definition DXILResourceAccess.cpp:412

static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI)

Definition DXILResourceAccess.cpp:448

static void createRawStore(IntrinsicInst *II, StoreInst *SI, Value *Offset)

Definition DXILResourceAccess.cpp:105

static bool runOnFunction(Function &F, bool PostInlining)

uint64_t IntrinsicInst * II

FunctionAnalysisManager FAM

#define INITIALIZE_PASS_DEPENDENCY(depName)

#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)

#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)

This file implements a set that has insertion order iteration characteristics.

Class for arbitrary precision integers.

LLVM_ABI APInt udiv(const APInt &RHS) const

Unsigned division operation.

AnalysisUsage & addRequired()

AnalysisUsage & addPreserved()

Add the specified Pass class to the set of analyses preserved by this pass.

LLVM Basic Block Representation.

const Instruction & back() const

This is the shared class of boolean and integer constants.

uint64_t getZExtValue() const

Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...

PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)

Definition DXILResourceAccess.cpp:519

A parsed version of the target data layout string in and methods for querying it.

ValueT lookup(const_arg_type_t< KeyT > Val) const

lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...

Analysis pass which computes a DominatorTree.

FunctionPass class - This class is used to implement most global optimizations.

an instruction for type-safe pointer arithmetic to access elements of arrays and structs

This provides a uniform API for creating instructions and inserting them into a basic block: either a...

LLVM_ABI const DataLayout & getDataLayout() const

Get the data layout of the module this instruction belongs to.

A wrapper class for inspecting calls to intrinsic functions.

An instruction for reading from memory.

static LLVM_ABI PoisonValue * get(Type *T)

Static factory methods - Return an 'poison' object of the specified type.

A set of analyses that are preserved following a run of a transformation pass.

static PreservedAnalyses all()

Construct a special preserved set that preserves all passes.

PreservedAnalyses & preserve()

Mark an analysis as preserved.

A vector that has set insertion semantics.

void clear()

Completely clear the SetVector.

bool insert(const value_type &X)

Insert a new element into the SetVector.

std::pair< iterator, bool > insert(PtrType Ptr)

Inserts Ptr if and only if there is no element in the container equal to Ptr.

SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.

This class consists of common code factored out of the SmallVector class to reduce code duplication b...

reference emplace_back(ArgTypes &&... Args)

void push_back(const T &Elt)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

An instruction for storing to memory.

StringRef - Represent a constant reference to a string, i.e.

static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)

This static method is the primary way to create a literal StructType.

Type * getTypeParameter(unsigned i) const

The instances of the Type class are immutable: once they are created, they are never changed.

Type * getScalarType() const

If this is a vector type, return the element type, otherwise return 'this'.

static LLVM_ABI IntegerType * getInt1Ty(LLVMContext &C)

A Use represents the edge between a Value definition and its users.

LLVM Value Representation.

Type * getType() const

All values are typed, get the type of this value.

LLVM_ABI void replaceAllUsesWith(Value *V)

Change all uses of this to point to a new Value.

LLVM_ABI StringRef getName() const

Return a constant reference to the value's name.

LLVM_ABI bool isTyped() const

TargetExtType * getHandleTy() const

dxil::ResourceKind getResourceKind() const

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

unsigned ID

LLVM IR allows to use arbitrary numbers as calling convention identifiers.

@ RTAccelerationStructure

const unsigned CBufferRowSizeInBytes

This is an optimization pass for GlobalISel generic memory operations.

decltype(auto) dyn_cast(const From &Val)

dyn_cast - Return the argument parameter cast to the specified type.

OuterAnalysisManagerProxy< ModuleAnalysisManager, Function > ModuleAnalysisManagerFunctionProxy

Provide the ModuleAnalysisManager to Function proxy.

auto dyn_cast_if_present(const Y &Val)

dyn_cast_if_present - Functionally identical to dyn_cast, except that a null (or none in the case ...

iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)

Make a range that does early increment to allow mutation of the underlying range without disrupting i...

auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)

auto reverse(ContainerTy &&C)

FunctionPass * createDXILResourceAccessLegacyPass()

Pass to update resource accesses to use load/store directly.

Definition DXILResourceAccess.cpp:562

void sort(IteratorTy Start, IteratorTy End)

@ RF_IgnoreMissingLocals

If this flag is set, the remapper ignores missing function-local entries (Argument,...

@ RF_NoModuleLevelChanges

If this flag is set, the remapper knows that only local values within a function (such as an instruct...

bool isa(const From &Val)

isa - Return true if the parameter to the template is an instance of one of the template type argu...

void RemapInstruction(Instruction *I, ValueToValueMapTy &VM, RemapFlags Flags=RF_None, ValueMapTypeRemapper *TypeMapper=nullptr, ValueMaterializer *Materializer=nullptr, const MetadataPredicate *IdentityMD=nullptr)

Convert the instruction operands from referencing the current values into those specified by VM.

ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy

decltype(auto) cast(const From &Val)

cast - Return the argument parameter cast to the specified type.

AnalysisManager< Function > FunctionAnalysisManager

Convenience typedef for the Function analysis manager.

LLVM_ABI void reportFatalUsageError(Error Err)

Report a fatal error that does not indicate a bug in LLVM.