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(->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 (->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 (.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 (.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 (->getType()->isPointerTy() ||
216 ->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.