23#define DEBUG_TYPE "dxil-legalize"
34 FI->replaceAllUsesWith(FI->getOperand(0));
49 ReplacedValues[
Op]->getType()->isIntegerTy())
56 NewOperands.push_back(ReplacedValues[
Op]);
59 unsigned NewBitWidth =
InstrType->getIntegerBitWidth();
64 "Replacement's BitWidth should be larger than Current.");
66 NewOperands.push_back(ConstantInt::get(
InstrType, NewValue));
68 assert(!
Op->getType()->isIntegerTy(8));
69 NewOperands.push_back(
Op);
75 if (Trunc->getDestTy()->isIntegerTy(8)) {
76 ReplacedValues[Trunc] = Trunc->getOperand(0);
83 if (!Store->getValueOperand()->getType()->isIntegerTy(8))
86 ProcessOperands(NewOperands);
87 Value *NewStore = Builder.CreateStore(NewOperands[0], NewOperands[1]);
88 ReplacedValues[Store] = NewStore;
94 Load &&
I.getType()->isIntegerTy(8)) {
96 ProcessOperands(NewOperands);
97 Type *ElementType = NewOperands[0]->getType();
99 ElementType = AI->getAllocatedType();
101 ElementType =
GEP->getSourceElementType();
103 if (ElementType->isArrayTy())
104 ElementType = ElementType->getArrayElementType();
105 LoadInst *NewLoad = Builder.CreateLoad(ElementType, NewOperands[0]);
106 ReplacedValues[Load] = NewLoad;
114 if (!(CE->getOpcode() == Instruction::GetElementPtr))
117 if (!
GEP->getSourceElementType()->isIntegerTy(8))
120 Type *ElementType = Load->getType();
123 uint32_t ElemSize = Load->getDataLayout().getTypeAllocSize(ElementType);
124 uint32_t Index = ByteOffset / ElemSize;
126 Value *PtrOperand =
GEP->getPointerOperand();
127 Type *GEPType =
GEP->getPointerOperandType();
130 GEPType = GV->getValueType();
132 GEPType = AI->getAllocatedType();
139 Value *NewGEP = Builder.CreateGEP(
140 GEPType, PtrOperand, {Builder.getInt32(0), Builder.getInt32(Index)},
141 GEP->getName(),
GEP->getNoWrapFlags());
143 LoadInst *NewLoad = Builder.CreateLoad(ElementType, NewGEP);
144 ReplacedValues[Load] = NewLoad;
145 Load->replaceAllUsesWith(NewLoad);
151 if (!
I.getType()->isIntegerTy(8))
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();
164 ReplacedValues[BO] = NewInst;
170 if (!
I.getType()->isIntegerTy(8))
173 ProcessOperands(NewOperands);
174 Value *NewInst = Builder.CreateSelect(Sel->getCondition(), NewOperands[1],
176 ReplacedValues[Sel] = NewInst;
182 if (!Cmp->getOperand(0)->getType()->isIntegerTy(8))
185 ProcessOperands(NewOperands);
187 Builder.CreateCmp(Cmp->getPredicate(), NewOperands[0], NewOperands[1]);
188 Cmp->replaceAllUsesWith(NewInst);
189 ReplacedValues[Cmp] = NewInst;
195 if (!Cast->getSrcTy()->isIntegerTy(8))
199 auto *Replacement = ReplacedValues[Cast->getOperand(0)];
200 if (Cast->getType() == Replacement->getType()) {
201 Cast->replaceAllUsesWith(Replacement);
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());
215 if (!
GEP->getType()->isPointerTy() ||
216 !
GEP->getSourceElementType()->isIntegerTy(8))
219 Value *BasePtr =
GEP->getPointerOperand();
220 if (ReplacedValues.
count(BasePtr))
221 BasePtr = ReplacedValues[BasePtr];
223 Type *ElementType = BasePtr->getType();
226 ElementType = AI->getAllocatedType();
228 ElementType = GV->getValueType();
230 Type *GEPType = ElementType;
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);
261 if (!AI || !AI->getAllocatedType()->isIntegerTy(8))
264 Type *SmallestType =
nullptr;
266 auto ProcessLoad = [&](
LoadInst *Load) {
267 for (
User *LU : Load->users()) {
270 Ty = Cast->getType();
272 if (CI->getIntrinsicID() == Intrinsic::memset)
289 for (
User *GU :
GEP->users()) {
301 auto *NewAlloca = Builder.CreateAlloca(SmallestType);
302 ReplacedValues[AI] = NewAlloca;
313 Value *Idx = Extract->getIndexOperand();
315 if (CI && CI->getBitWidth() == 64) {
317 int64_t IndexValue = CI->getSExtValue();
320 Value *NewExtract = Builder.CreateExtractElement(
321 Extract->getVectorOperand(), Idx32, Extract->getName());
330 Value *Idx = Insert->getOperand(2);
332 if (CI && CI->getBitWidth() == 64) {
333 int64_t IndexValue = CI->getSExtValue();
337 Value *Insert32Index = Builder.CreateInsertElement(
338 Insert->getOperand(0), Insert->getOperand(1), Idx32,
341 Insert->replaceAllUsesWith(Insert32Index);
357 const DataLayout &
DL = Builder.GetInsertBlock()->getModule()->getDataLayout();
362 "Expected Val to be an Alloca or Global Variable");
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");
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");
387 assert(DstElemTy == SrcElemTy &&
388 "The element types of Src and Dst arrays must match");
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");
397 uint64_t NumElemsToCopy = ByteLength / DstElemByteSize;
398 assert(ByteLength % DstElemByteSize == 0 &&
399 "memcpy length must be divisible by array element type");
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);
414 Builder.GetInsertBlock()->getModule()->getDataLayout();
419 assert(Alloca &&
"Expected memset on an Alloca");
421 "Expected for memset size to match DataLayout size");
425 assert(ArrTy &&
"Expected Alloca for an Array Type");
427 Type *ElemTy = ArrTy->getElementType();
430 [[maybe_unused]]
uint64_t ElemSize =
DL.getTypeStoreSize(ElemTy);
432 assert(ElemSize > 0 &&
"Size must be set");
433 assert(OrigSize == ElemSize *
Size &&
"Size in bytes must match");
435 Value *TypedVal = Val;
437 if (Val->
getType() != ElemTy) {
438 if (ReplacedValues[Val]) {
442 TypedVal = ReplacedValues[Val];
448 TypedVal = Builder.CreateIntCast(Val, ElemTy,
false);
453 Value *Zero = Builder.getInt32(0);
455 Value *
Ptr = Builder.CreateGEP(ArrTy, Dst, {Zero,
Offset},
"gep");
456 Builder.CreateStore(TypedVal,
Ptr);
472 if (
ID != Intrinsic::memcpy)
479 assert(
Length &&
"Expected Length to be a ConstantInt");
482 assert(IsVolatile &&
"Expected IsVolatile to be a ConstantInt");
483 assert(IsVolatile->getZExtValue() == 0 &&
"Expected IsVolatile to be false");
498 if (
ID != Intrinsic::memset)
505 assert(
Size &&
"Expected Size to be a ConstantInt");
515 if (
ID != Instruction::FNeg)
519 Value *In =
I.getOperand(0);
520 Value *Zero = ConstantFP::get(In->getType(), -0.0);
521 I.replaceAllUsesWith(Builder.CreateFSub(Zero, In));
531 if (BitCast->getDestTy() ==
533 BitCast->getSrcTy()->isIntegerTy(64)) {
535 ReplacedValues[BitCast] = BitCast->getOperand(0);
544 if (VecTy && VecTy->getElementType()->isIntegerTy(32) &&
545 VecTy->getNumElements() == 2) {
547 unsigned Idx = Index->getZExtValue();
550 auto *Replacement = ReplacedValues[Extract->getVectorOperand()];
551 assert(Replacement &&
"The BitCast replacement should have been set "
552 "before working on ExtractElementInst.");
554 Value *LowBytes = Builder.CreateTrunc(
556 ReplacedValues[Extract] = LowBytes;
559 Value *LogicalShiftRight = Builder.CreateLShr(
562 Replacement->getType(),
563 APInt(Replacement->getType()->getIntegerBitWidth(), 32)));
564 Value *HighBytes = Builder.CreateTrunc(
566 ReplacedValues[Extract] = HighBytes;
569 Extract->replaceAllUsesWith(ReplacedValues[Extract]);
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();
605 ArrayTy = GlobalVarPtrOp->getValueType();
607 ArrayTy = AllocaPtrOp->getAllocatedType();
615 "Expected array element type to be the same as to the scalar load or "
621 I.setOperand(PtrOpIndex,
GEP);
626class DXILLegalizationPipeline {
629 DXILLegalizationPipeline() { initializeLegalizationPipeline(); }
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);
644 Inst->eraseFromParent();
650 enum LegalizationStage { Stage1 = 0, Stage2 = 1, NumStages };
652 using LegalizationFnTy =
653 std::function<bool(Instruction &, SmallVectorImpl<Instruction *> &,
654 DenseMap<Value *, Value *> &)>;
658 void initializeLegalizationPipeline() {
671 LegalizationPipeline[Stage2].push_back(
681 DXILLegalizeLegacy() : FunctionPass(ID) {}
689 DXILLegalizationPipeline DXLegalize;
690 bool MadeChanges = DXLegalize.runLegalizationPipeline(
F);
697bool DXILLegalizeLegacy::runOnFunction(
Function &
F) {
698 DXILLegalizationPipeline DXLegalize;
699 return DXLegalize.runLegalizationPipeline(
F);
702char DXILLegalizeLegacy::ID = 0;
710 return new DXILLegalizeLegacy();
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)
static bool downcastI64toI32InsertExtractElements(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &)
static void emitMemcpyExpansion(IRBuilder<> &Builder, Value *Dst, Value *Src, ConstantInt *Length)
static bool upcastI8AllocasAndUses(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &ReplacedValues)
static bool legalizeMemCpy(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &ReplacedValues)
static bool legalizeMemSet(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &ReplacedValues)
static void emitMemsetExpansion(IRBuilder<> &Builder, Value *Dst, Value *Val, ConstantInt *SizeCI, DenseMap< Value *, Value * > &ReplacedValues)
static bool legalizeScalarLoadStoreOnArrays(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &)
static bool legalizeGetHighLowi64Bytes(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &ReplacedValues)
static bool legalizeFreeze(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * >)
static bool updateFnegToFsub(Instruction &I, SmallVectorImpl< Instruction * > &ToRemove, DenseMap< Value *, Value * > &)
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)
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.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - 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<X> - 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.