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

1

2

3

4

5

6

7

8

21#include

22

23#define DEBUG_TYPE "dxil-legalize"

24

25using namespace llvm;

26

31 if (!FI)

32 return false;

33

34 FI->replaceAllUsesWith(FI->getOperand(0));

36 return true;

37}

38

42

45

46 for (unsigned OpIdx = 0; OpIdx < I.getNumOperands(); ++OpIdx) {

48 if (ReplacedValues.count(Op) &&

49 ReplacedValues[Op]->getType()->isIntegerTy())

50 InstrType = ReplacedValues[Op]->getType();

51 }

52

53 for (unsigned OpIdx = 0; OpIdx < I.getNumOperands(); ++OpIdx) {

55 if (ReplacedValues.count(Op))

56 NewOperands.push_back(ReplacedValues[Op]);

59 unsigned NewBitWidth = InstrType->getIntegerBitWidth();

60

61

62

63 assert(NewBitWidth > Value.getBitWidth() &&

64 "Replacement's BitWidth should be larger than Current.");

65 APInt NewValue = Value.sext(NewBitWidth);

66 NewOperands.push_back(ConstantInt::get(InstrType, NewValue));

67 } else {

68 assert(Op->getType()->isIntegerTy(8));

69 NewOperands.push_back(Op);

70 }

71 }

72 };

75 if (Trunc->getDestTy()->isIntegerTy(8)) {

76 ReplacedValues[Trunc] = Trunc->getOperand(0);

78 return true;

79 }

80 }

81

83 if (!Store->getValueOperand()->getType()->isIntegerTy(8))

84 return false;

86 ProcessOperands(NewOperands);

87 Value *NewStore = Builder.CreateStore(NewOperands[0], NewOperands[1]);

88 ReplacedValues[Store] = NewStore;

90 return true;

91 }

92

94 Load && I.getType()->isIntegerTy(8)) {

96 ProcessOperands(NewOperands);

97 Type *ElementType = NewOperands[0]->getType();

99 ElementType = AI->getAllocatedType();

101 ElementType = GEP->getSourceElementType();

102 }

103 if (ElementType->isArrayTy())

104 ElementType = ElementType->getArrayElementType();

105 LoadInst *NewLoad = Builder.CreateLoad(ElementType, NewOperands[0]);

106 ReplacedValues[Load] = NewLoad;

108 return true;

109 }

110

114 if (!(CE->getOpcode() == Instruction::GetElementPtr))

115 return false;

117 if (GEP->getSourceElementType()->isIntegerTy(8))

118 return false;

119

120 Type *ElementType = Load->getType();

123 uint32_t ElemSize = Load->getDataLayout().getTypeAllocSize(ElementType);

124 uint32_t Index = ByteOffset / ElemSize;

125

126 Value *PtrOperand = GEP->getPointerOperand();

127 Type *GEPType = GEP->getPointerOperandType();

128

130 GEPType = GV->getValueType();

132 GEPType = AI->getAllocatedType();

133

135 GEPType = ArrTy;

136 else

137 GEPType = ArrayType::get(ElementType, 1);

138

139 Value *NewGEP = Builder.CreateGEP(

140 GEPType, PtrOperand, {Builder.getInt32(0), Builder.getInt32(Index)},

141 GEP->getName(), GEP->getNoWrapFlags());

142

143 LoadInst *NewLoad = Builder.CreateLoad(ElementType, NewGEP);

144 ReplacedValues[Load] = NewLoad;

145 Load->replaceAllUsesWith(NewLoad);

147 return true;

148 }

149

151 if (I.getType()->isIntegerTy(8))

152 return false;

154 ProcessOperands(NewOperands);

156 Builder.CreateBinOp(BO->getOpcode(), NewOperands[0], NewOperands[1]);

159 if (NewBO && OBO->hasNoSignedWrap())

160 NewBO->setHasNoSignedWrap();

161 if (NewBO && OBO->hasNoUnsignedWrap())

162 NewBO->setHasNoUnsignedWrap();

163 }

164 ReplacedValues[BO] = NewInst;

166 return true;

167 }

168

170 if (I.getType()->isIntegerTy(8))

171 return false;

173 ProcessOperands(NewOperands);

174 Value *NewInst = Builder.CreateSelect(Sel->getCondition(), NewOperands[1],

175 NewOperands[2]);

176 ReplacedValues[Sel] = NewInst;

178 return true;

179 }

180

182 if (!Cmp->getOperand(0)->getType()->isIntegerTy(8))

183 return false;

185 ProcessOperands(NewOperands);

187 Builder.CreateCmp(Cmp->getPredicate(), NewOperands[0], NewOperands[1]);

188 Cmp->replaceAllUsesWith(NewInst);

189 ReplacedValues[Cmp] = NewInst;

191 return true;

192 }

193

195 if (!Cast->getSrcTy()->isIntegerTy(8))

196 return false;

197

199 auto *Replacement = ReplacedValues[Cast->getOperand(0)];

200 if (Cast->getType() == Replacement->getType()) {

201 Cast->replaceAllUsesWith(Replacement);

202 return true;

203 }

204

205 Value *AdjustedCast = nullptr;

206 if (Cast->getOpcode() == Instruction::ZExt)

207 AdjustedCast = Builder.CreateZExtOrTrunc(Replacement, Cast->getType());

208 if (Cast->getOpcode() == Instruction::SExt)

209 AdjustedCast = Builder.CreateSExtOrTrunc(Replacement, Cast->getType());

210

211 if (AdjustedCast)

213 }

215 if (GEP->getType()->isPointerTy() ||

216 GEP->getSourceElementType()->isIntegerTy(8))

217 return false;

218

219 Value *BasePtr = GEP->getPointerOperand();

220 if (ReplacedValues.count(BasePtr))

221 BasePtr = ReplacedValues[BasePtr];

222

223 Type *ElementType = BasePtr->getType();

224

226 ElementType = AI->getAllocatedType();

228 ElementType = GV->getValueType();

229

230 Type *GEPType = ElementType;

233 else

234 GEPType = ArrayType::get(ElementType, 1);

235

237

238

239

240

241 assert(Offset && "Offset is expected to be a ConstantInt");

243 uint32_t ElemSize = GEP->getDataLayout().getTypeAllocSize(ElementType);

244 assert(ElemSize > 0 && "ElementSize must be set");

245 uint32_t Index = ByteOffset / ElemSize;

246 Value *NewGEP = Builder.CreateGEP(

247 GEPType, BasePtr, {Builder.getInt32(0), Builder.getInt32(Index)},

248 GEP->getName(), GEP->getNoWrapFlags());

249 ReplacedValues[GEP] = NewGEP;

250 GEP->replaceAllUsesWith(NewGEP);

252 return true;

253 }

254 return false;

255}

256

261 if (!AI || !AI->getAllocatedType()->isIntegerTy(8))

262 return false;

263

264 Type *SmallestType = nullptr;

265

266 auto ProcessLoad = [&](LoadInst *Load) {

267 for (User *LU : Load->users()) {

268 Type *Ty = nullptr;

270 Ty = Cast->getType();

272 if (CI->getIntrinsicID() == Intrinsic::memset)

274 }

275

276 if (!Ty)

277 continue;

278

279 if (!SmallestType ||

281 SmallestType = Ty;

282 }

283 };

284

287 ProcessLoad(Load);

289 for (User *GU : GEP->users()) {

291 ProcessLoad(Load);

292 }

293 }

294 }

295

296 if (!SmallestType)

297 return false;

298

299

301 auto *NewAlloca = Builder.CreateAlloca(SmallestType);

302 ReplacedValues[AI] = NewAlloca;

304 return true;

305}

306

307static bool

311

313 Value *Idx = Extract->getIndexOperand();

315 if (CI && CI->getBitWidth() == 64) {

317 int64_t IndexValue = CI->getSExtValue();

318 auto *Idx32 =

320 Value *NewExtract = Builder.CreateExtractElement(

321 Extract->getVectorOperand(), Idx32, Extract->getName());

322

325 return true;

326 }

327 }

328

330 Value *Idx = Insert->getOperand(2);

332 if (CI && CI->getBitWidth() == 64) {

333 int64_t IndexValue = CI->getSExtValue();

334 auto *Idx32 =

337 Value *Insert32Index = Builder.CreateInsertElement(

338 Insert->getOperand(0), Insert->getOperand(1), Idx32,

339 Insert->getName());

340

341 Insert->replaceAllUsesWith(Insert32Index);

343 return true;

344 }

345 }

346 return false;

347}

348

351

353

354 if (ByteLength == 0)

355 return;

356

357 const DataLayout &DL = Builder.GetInsertBlock()->getModule()->getDataLayout();

358

359 auto GetArrTyFromVal = [](Value *Val) -> ArrayType * {

362 "Expected Val to be an Alloca or Global Variable");

367 return nullptr;

368 };

369

370 ArrayType *DstArrTy = GetArrTyFromVal(Dst);

371 assert(DstArrTy && "Expected Dst of memcpy to be a Pointer to an Array Type");

373 assert(!DstGlobalVar->isConstant() &&

374 "The Dst of memcpy must not be a constant Global Variable");

375 [[maybe_unused]] ArrayType *SrcArrTy = GetArrTyFromVal(Src);

376 assert(SrcArrTy && "Expected Src of memcpy to be a Pointer to an Array Type");

377

378 Type *DstElemTy = DstArrTy->getElementType();

379 uint64_t DstElemByteSize = DL.getTypeStoreSize(DstElemTy);

380 assert(DstElemByteSize > 0 && "Dst element type store size must be set");

381 Type *SrcElemTy = SrcArrTy->getElementType();

382 [[maybe_unused]] uint64_t SrcElemByteSize = DL.getTypeStoreSize(SrcElemTy);

383 assert(SrcElemByteSize > 0 && "Src element type store size must be set");

384

385

386

387 assert(DstElemTy == SrcElemTy &&

388 "The element types of Src and Dst arrays must match");

389

390 [[maybe_unused]] uint64_t DstArrNumElems = DstArrTy->getArrayNumElements();

391 assert(DstElemByteSize * DstArrNumElems >= ByteLength &&

392 "Dst array size must be at least as large as the memcpy length");

393 [[maybe_unused]] uint64_t SrcArrNumElems = SrcArrTy->getArrayNumElements();

394 assert(SrcElemByteSize * SrcArrNumElems >= ByteLength &&

395 "Src array size must be at least as large as the memcpy length");

396

397 uint64_t NumElemsToCopy = ByteLength / DstElemByteSize;

398 assert(ByteLength % DstElemByteSize == 0 &&

399 "memcpy length must be divisible by array element type");

400 for (uint64_t I = 0; I < NumElemsToCopy; ++I) {

402 Builder.getInt32(I)};

403 Value *SrcPtr = Builder.CreateInBoundsGEP(SrcArrTy, Src, Indices, "gep");

404 Value *SrcVal = Builder.CreateLoad(SrcElemTy, SrcPtr);

405 Value *DstPtr = Builder.CreateInBoundsGEP(DstArrTy, Dst, Indices, "gep");

406 Builder.CreateStore(SrcVal, DstPtr);

407 }

408}

409

414 Builder.GetInsertBlock()->getModule()->getDataLayout();

416

418

419 assert(Alloca && "Expected memset on an Alloca");

421 "Expected for memset size to match DataLayout size");

422

425 assert(ArrTy && "Expected Alloca for an Array Type");

426

427 Type *ElemTy = ArrTy->getElementType();

428 uint64_t Size = ArrTy->getArrayNumElements();

429

430 [[maybe_unused]] uint64_t ElemSize = DL.getTypeStoreSize(ElemTy);

431

432 assert(ElemSize > 0 && "Size must be set");

433 assert(OrigSize == ElemSize * Size && "Size in bytes must match");

434

435 Value *TypedVal = Val;

436

437 if (Val->getType() != ElemTy) {

438 if (ReplacedValues[Val]) {

439

440

441

442 TypedVal = ReplacedValues[Val];

443

444 } else {

445

446

447

448 TypedVal = Builder.CreateIntCast(Val, ElemTy, false);

449 }

450 }

451

453 Value *Zero = Builder.getInt32(0);

455 Value *Ptr = Builder.CreateGEP(ArrTy, Dst, {Zero, Offset}, "gep");

456 Builder.CreateStore(TypedVal, Ptr);

457 }

458}

459

460

461

462

466

468 if (!CI)

469 return false;

470

472 if (ID != Intrinsic::memcpy)

473 return false;

474

479 assert(Length && "Expected Length to be a ConstantInt");

480 [[maybe_unused]] ConstantInt *IsVolatile =

482 assert(IsVolatile && "Expected IsVolatile to be a ConstantInt");

483 assert(IsVolatile->getZExtValue() == 0 && "Expected IsVolatile to be false");

486 return true;

487}

488

492

494 if (!CI)

495 return false;

496

498 if (ID != Intrinsic::memset)

499 return false;

500

505 assert(Size && "Expected Size to be a ConstantInt");

508 return true;

509}

510

515 if (ID != Instruction::FNeg)

516 return false;

517

519 Value *In = I.getOperand(0);

520 Value *Zero = ConstantFP::get(In->getType(), -0.0);

521 I.replaceAllUsesWith(Builder.CreateFSub(Zero, In));

523 return true;

524}

525

526static bool

531 if (BitCast->getDestTy() ==

533 BitCast->getSrcTy()->isIntegerTy(64)) {

535 ReplacedValues[BitCast] = BitCast->getOperand(0);

536 return true;

537 }

538 }

539

542 return false;

544 if (VecTy && VecTy->getElementType()->isIntegerTy(32) &&

545 VecTy->getNumElements() == 2) {

547 unsigned Idx = Index->getZExtValue();

549

550 auto *Replacement = ReplacedValues[Extract->getVectorOperand()];

551 assert(Replacement && "The BitCast replacement should have been set "

552 "before working on ExtractElementInst.");

553 if (Idx == 0) {

554 Value *LowBytes = Builder.CreateTrunc(

556 ReplacedValues[Extract] = LowBytes;

557 } else {

559 Value *LogicalShiftRight = Builder.CreateLShr(

560 Replacement,

561 ConstantInt::get(

562 Replacement->getType(),

563 APInt(Replacement->getType()->getIntegerBitWidth(), 32)));

564 Value *HighBytes = Builder.CreateTrunc(

566 ReplacedValues[Extract] = HighBytes;

567 }

569 Extract->replaceAllUsesWith(ReplacedValues[Extract]);

570 return true;

571 }

572 }

573 }

574 return false;

575}

576

577static bool

581

583 unsigned PtrOpIndex;

584 [[maybe_unused]] Type *LoadStoreTy;

586 PtrOp = LI->getPointerOperand();

587 PtrOpIndex = LI->getPointerOperandIndex();

588 LoadStoreTy = LI->getType();

590 PtrOp = SI->getPointerOperand();

591 PtrOpIndex = SI->getPointerOperandIndex();

592 LoadStoreTy = SI->getValueOperand()->getType();

593 } else

594 return false;

595

596

597

598

599

601 return false;

602

603 Type *ArrayTy;

605 ArrayTy = GlobalVarPtrOp->getValueType();

607 ArrayTy = AllocaPtrOp->getAllocatedType();

608 else

609 return false;

610

612 return false;

613

615 "Expected array element type to be the same as to the scalar load or "

616 "store type");

617

621 I.setOperand(PtrOpIndex, GEP);

622 return true;

623}

624

625namespace {

626class DXILLegalizationPipeline {

627

628public:

629 DXILLegalizationPipeline() { initializeLegalizationPipeline(); }

630

631 bool runLegalizationPipeline(Function &F) {

632 bool MadeChange = false;

634 DenseMap<Value *, Value *> ReplacedValues;

635 for (int Stage = 0; Stage < NumStages; ++Stage) {

637 ReplacedValues.clear();

639 for (auto &LegalizationFn : LegalizationPipeline[Stage])

640 MadeChange |= LegalizationFn(I, ToRemove, ReplacedValues);

641 }

642

644 Inst->eraseFromParent();

645 }

646 return MadeChange;

647 }

648

649private:

650 enum LegalizationStage { Stage1 = 0, Stage2 = 1, NumStages };

651

652 using LegalizationFnTy =

653 std::function<bool(Instruction &, SmallVectorImpl<Instruction *> &,

654 DenseMap<Value *, Value *> &)>;

655

657

658 void initializeLegalizationPipeline() {

660 LegalizationPipeline[Stage1].push_back(fixI8UseChain);

662 LegalizationPipeline[Stage1].push_back(legalizeFreeze);

663 LegalizationPipeline[Stage1].push_back(legalizeMemCpy);

664 LegalizationPipeline[Stage1].push_back(legalizeMemSet);

666

667

668

669

670

671 LegalizationPipeline[Stage2].push_back(

674 }

675};

676

677class DXILLegalizeLegacy : public FunctionPass {

678

679public:

681 DXILLegalizeLegacy() : FunctionPass(ID) {}

682

683 static char ID;

684};

685}

686

689 DXILLegalizationPipeline DXLegalize;

690 bool MadeChanges = DXLegalize.runLegalizationPipeline(F);

691 if (!MadeChanges)

694 return PA;

695}

696

697bool DXILLegalizeLegacy::runOnFunction(Function &F) {

698 DXILLegalizationPipeline DXLegalize;

699 return DXLegalize.runLegalizationPipeline(F);

700}

701

702char DXILLegalizeLegacy::ID = 0;

703

705 false)

708

710 return new DXILLegalizeLegacy();

711}

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

This file implements a class to represent arbitrary precision integral constant values and operations...

ReachingDefInfo InstSet & ToRemove

MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL

Expand Atomic instructions

This file contains the declarations for the subclasses of Constant, which represent the different fla...

static bool fixI8UseChain(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &ReplacedValues)

Definition DXILLegalizePass.cpp:39

static bool downcastI64toI32InsertExtractElements(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &)

Definition DXILLegalizePass.cpp:308

static void emitMemcpyExpansion(IRBuilder<> &Builder, Value *Dst, Value *Src, ConstantInt *Length)

Definition DXILLegalizePass.cpp:349

static bool upcastI8AllocasAndUses(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &ReplacedValues)

Definition DXILLegalizePass.cpp:257

static bool legalizeMemCpy(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &ReplacedValues)

Definition DXILLegalizePass.cpp:463

static bool legalizeMemSet(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &ReplacedValues)

Definition DXILLegalizePass.cpp:489

static void emitMemsetExpansion(IRBuilder<> &Builder, Value *Dst, Value *Val, ConstantInt *SizeCI, DenseMap< Value *, Value * > &ReplacedValues)

Definition DXILLegalizePass.cpp:410

static bool legalizeScalarLoadStoreOnArrays(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &)

Definition DXILLegalizePass.cpp:578

static bool legalizeGetHighLowi64Bytes(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &ReplacedValues)

Definition DXILLegalizePass.cpp:527

static bool legalizeFreeze(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * >)

Definition DXILLegalizePass.cpp:27

static bool updateFnegToFsub(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &)

Definition DXILLegalizePass.cpp:511

static bool runOnFunction(Function &F, bool PostInlining)

Module.h This file contains the declarations for the Module class.

MachineInstr unsigned OpIdx

FunctionAnalysisManager FAM

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

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

Class for arbitrary precision integers.

an instruction to allocate memory on the stack

Type * getAllocatedType() const

Return the type that is being allocated by the instruction.

LLVM_ABI std::optional< TypeSize > getAllocationSize(const DataLayout &DL) const

Get allocation size in bytes.

static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)

This static method is the primary way to construct an ArrayType.

Value * getArgOperand(unsigned i) const

LLVM_ABI Intrinsic::ID getIntrinsicID() const

Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...

This class represents a function call, abstracting a target machine's calling convention.

This is the base class for all instructions that perform data casts.

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 &FAM)

Definition DXILLegalizePass.cpp:687

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

size_type count(const_arg_type_t< KeyT > Val) const

Return 1 if the specified key is in the map, 0 otherwise.

static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)

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

static GEPNoWrapFlags all()

static GetElementPtrInst * Create(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)

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

static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)

This static method is the primary way of constructing an IntegerType.

An instruction for reading from memory.

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.

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

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

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

static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)

Type * getArrayElementType() const

bool isSingleValueType() const

Return true if the type is a valid type for a register in codegen.

LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY

Return the basic size of this type if it is a primitive type.

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.

iterator_range< user_iterator > users()

unsigned ID

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

InstrType

This represents what is and is not supported when finding similarity in Instructions.

This is an optimization pass for GlobalISel generic memory operations.

FunctionPass * createDXILLegalizeLegacyPass()

Pass to Legalize DXIL by remove i8 truncations and i64 insert/extract elements.

Definition DXILLegalizePass.cpp:709

decltype(auto) dyn_cast(const From &Val)

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

auto reverse(ContainerTy &&C)

class LLVM_GSL_OWNER SmallVector

Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...

bool isa(const From &Val)

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

DWARFExpression::Operation Op

AnalysisManager< Function > FunctionAnalysisManager

Convenience typedef for the Function analysis manager.