23#define DEBUG_TYPE "dxil-legalize"
30 auto *FI = dyn_cast<FreezeInst>(&
I);
34 FI->replaceAllUsesWith(FI->getOperand(0));
49 ReplacedValues[
Op]->getType()->isIntegerTy())
56 NewOperands.push_back(ReplacedValues[
Op]);
57 else if (
auto *Imm = dyn_cast<ConstantInt>(
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);
74 if (
auto *Trunc = dyn_cast<TruncInst>(&
I)) {
75 if (Trunc->getDestTy()->isIntegerTy(8)) {
76 ReplacedValues[Trunc] = Trunc->getOperand(0);
82 if (
auto *Store = dyn_cast<StoreInst>(&
I)) {
83 if (!Store->getValueOperand()->getType()->isIntegerTy(8))
86 ProcessOperands(NewOperands);
88 ReplacedValues[Store] = NewStore;
93 if (
auto *Load = dyn_cast<LoadInst>(&
I);
94 Load &&
I.getType()->isIntegerTy(8)) {
96 ProcessOperands(NewOperands);
97 Type *ElementType = NewOperands[0]->getType();
98 if (
auto *AI = dyn_cast<AllocaInst>(NewOperands[0]))
99 ElementType = AI->getAllocatedType();
100 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(NewOperands[0])) {
101 ElementType =
GEP->getSourceElementType();
103 if (ElementType->isArrayTy())
104 ElementType = ElementType->getArrayElementType();
106 ReplacedValues[Load] = NewLoad;
111 if (
auto *Load = dyn_cast<LoadInst>(&
I);
112 Load && isa<ConstantExpr>(Load->getPointerOperand())) {
113 auto *CE = dyn_cast<ConstantExpr>(Load->getPointerOperand());
114 if (!(CE->getOpcode() == Instruction::GetElementPtr))
116 auto *
GEP = dyn_cast<GEPOperator>(CE);
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();
129 if (
auto *GV = dyn_cast<GlobalVariable>(PtrOperand))
130 GEPType = GV->getValueType();
131 if (
auto *AI = dyn_cast<AllocaInst>(PtrOperand))
132 GEPType = AI->getAllocatedType();
134 if (
auto *ArrTy = dyn_cast<ArrayType>(GEPType))
137 GEPType = ArrayType::get(ElementType, 1);
141 GEP->getName(),
GEP->getNoWrapFlags());
144 ReplacedValues[Load] = NewLoad;
145 Load->replaceAllUsesWith(NewLoad);
150 if (
auto *BO = dyn_cast<BinaryOperator>(&
I)) {
151 if (!
I.getType()->isIntegerTy(8))
154 ProcessOperands(NewOperands);
156 Builder.
CreateBinOp(BO->getOpcode(), NewOperands[0], NewOperands[1]);
157 if (
auto *OBO = dyn_cast<OverflowingBinaryOperator>(&
I)) {
158 auto *NewBO = dyn_cast<BinaryOperator>(NewInst);
159 if (NewBO && OBO->hasNoSignedWrap())
160 NewBO->setHasNoSignedWrap();
161 if (NewBO && OBO->hasNoUnsignedWrap())
162 NewBO->setHasNoUnsignedWrap();
164 ReplacedValues[BO] = NewInst;
169 if (
auto *Sel = dyn_cast<SelectInst>(&
I)) {
170 if (!
I.getType()->isIntegerTy(8))
173 ProcessOperands(NewOperands);
176 ReplacedValues[Sel] = NewInst;
181 if (
auto *Cmp = dyn_cast<CmpInst>(&
I)) {
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;
194 if (
auto *Cast = dyn_cast<CastInst>(&
I)) {
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)
208 if (Cast->getOpcode() == Instruction::SExt)
214 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(&
I)) {
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();
225 if (
auto *AI = dyn_cast<AllocaInst>(BasePtr))
226 ElementType = AI->getAllocatedType();
227 if (
auto *GV = dyn_cast<GlobalVariable>(BasePtr))
228 ElementType = GV->getValueType();
230 Type *GEPType = ElementType;
231 if (
auto *ArrTy = dyn_cast<ArrayType>(ElementType))
232 ElementType = ArrTy->getArrayElementType();
234 GEPType = ArrayType::get(ElementType, 1);
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;
248 GEP->getName(),
GEP->getNoWrapFlags());
249 ReplacedValues[
GEP] = NewGEP;
250 GEP->replaceAllUsesWith(NewGEP);
260 auto *AI = dyn_cast<AllocaInst>(&
I);
261 if (!AI || !AI->getAllocatedType()->isIntegerTy(8))
264 Type *SmallestType =
nullptr;
266 auto ProcessLoad = [&](
LoadInst *Load) {
267 for (
User *LU : Load->users()) {
269 if (
CastInst *Cast = dyn_cast<CastInst>(LU))
270 Ty = Cast->getType();
271 else if (
CallInst *CI = dyn_cast<CallInst>(LU)) {
272 if (CI->getIntrinsicID() == Intrinsic::memset)
285 for (
User *U : AI->users()) {
286 if (
auto *Load = dyn_cast<LoadInst>(U))
288 else if (
auto *
GEP = dyn_cast<GetElementPtrInst>(U)) {
289 for (
User *GU :
GEP->users()) {
290 if (
auto *Load = dyn_cast<LoadInst>(GU))
302 ReplacedValues[AI] = NewAlloca;
312 if (
auto *Extract = dyn_cast<ExtractElementInst>(&
I)) {
313 Value *
Idx = Extract->getIndexOperand();
314 auto *CI = dyn_cast<ConstantInt>(
Idx);
315 if (CI && CI->getBitWidth() == 64) {
317 int64_t IndexValue = CI->getSExtValue();
321 Extract->getVectorOperand(), Idx32, Extract->getName());
329 if (
auto *Insert = dyn_cast<InsertElementInst>(&
I)) {
331 auto *CI = dyn_cast<ConstantInt>(
Idx);
332 if (CI && CI->getBitWidth() == 64) {
333 int64_t IndexValue = CI->getSExtValue();
338 Insert->getOperand(0), Insert->getOperand(1), Idx32,
341 Insert->replaceAllUsesWith(Insert32Index);
360 assert(isa<AllocaInst>(Val) ||
361 isa<GlobalVariable>(Val) &&
362 "Expected Val to be an Alloca or Global Variable");
363 if (
auto *Alloca = dyn_cast<AllocaInst>(Val))
364 return dyn_cast<ArrayType>(Alloca->getAllocatedType());
365 if (
auto *GlobalVar = dyn_cast<GlobalVariable>(Val))
366 return dyn_cast<ArrayType>(GlobalVar->getValueType());
370 ArrayType *DstArrTy = GetArrTyFromVal(Dst);
371 assert(DstArrTy &&
"Expected Dst of memcpy to be a Pointer to an Array Type");
372 if (
auto *DstGlobalVar = dyn_cast<GlobalVariable>(Dst))
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");
417 AllocaInst *Alloca = dyn_cast<AllocaInst>(Dst);
419 assert(Alloca &&
"Expected memset on an Alloca");
421 "Expected for memset size to match DataLayout size");
424 ArrayType *ArrTy = dyn_cast<ArrayType>(AllocatedTy);
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];
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));
530 if (
auto *BitCast = dyn_cast<BitCastInst>(&
I)) {
531 if (BitCast->getDestTy() ==
535 ReplacedValues[BitCast] = BitCast->getOperand(0);
540 if (
auto *Extract = dyn_cast<ExtractElementInst>(&
I)) {
541 if (!dyn_cast<BitCastInst>(Extract->getVectorOperand()))
543 auto *VecTy = dyn_cast<FixedVectorType>(Extract->getVectorOperandType());
544 if (VecTy && VecTy->getElementType()->isIntegerTy(32) &&
545 VecTy->getNumElements() == 2) {
546 if (
auto *Index = dyn_cast<ConstantInt>(Extract->getIndexOperand())) {
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.");
556 ReplacedValues[Extract] = LowBytes;
562 Replacement->getType(),
563 APInt(Replacement->getType()->getIntegerBitWidth(), 32)));
566 ReplacedValues[Extract] = HighBytes;
569 Extract->replaceAllUsesWith(ReplacedValues[Extract]);
584 [[maybe_unused]]
Type *LoadStoreTy;
585 if (
auto *LI = dyn_cast<LoadInst>(&
I)) {
586 PtrOp = LI->getPointerOperand();
587 PtrOpIndex = LI->getPointerOperandIndex();
588 LoadStoreTy = LI->getType();
589 }
else if (
auto *SI = dyn_cast<StoreInst>(&
I)) {
590 PtrOp = SI->getPointerOperand();
591 PtrOpIndex = SI->getPointerOperandIndex();
592 LoadStoreTy = SI->getValueOperand()->getType();
604 if (
auto *GlobalVarPtrOp = dyn_cast<GlobalVariable>(PtrOp))
605 ArrayTy = GlobalVarPtrOp->getValueType();
606 else if (
auto *AllocaPtrOp = dyn_cast<AllocaInst>(PtrOp))
607 ArrayTy = AllocaPtrOp->getAllocatedType();
611 if (!isa<ArrayType>(ArrayTy))
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;
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 =
658 void initializeLegalizationPipeline() {
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...
ReachingDefAnalysis 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 * > &)
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
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.
A container for analyses that lazily runs them and caches their results.
LLVM_ABI const Module * getModule() const
Return the module owning the function this basic block belongs to, or nullptr if the function does no...
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...
This class represents an Operation in the Expression.
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.
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
static GEPNoWrapFlags all()
static GetElementPtrInst * Create(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Value * CreateFSub(Value *L, Value *R, const Twine &Name="", MDNode *FPMD=nullptr)
Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")
AllocaInst * CreateAlloca(Type *Ty, unsigned AddrSpace, Value *ArraySize=nullptr, const Twine &Name="")
Value * CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name="")
Value * CreateZExtOrTrunc(Value *V, Type *DestTy, const Twine &Name="")
Create a ZExt or Trunc from the integer value V to DestTy.
LLVM_ABI Value * CreateSelect(Value *C, Value *True, Value *False, const Twine &Name="", Instruction *MDFrom=nullptr)
Value * CreateLShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
BasicBlock * GetInsertBlock() const
Value * CreateInBoundsGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="")
Value * CreateGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="", GEPNoWrapFlags NW=GEPNoWrapFlags::none())
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Value * CreateCmp(CmpInst::Predicate Pred, Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Value * CreateTrunc(Value *V, Type *DestTy, const Twine &Name="", bool IsNUW=false, bool IsNSW=false)
Value * CreateBinOp(Instruction::BinaryOps Opc, Value *LHS, Value *RHS, const Twine &Name="", MDNode *FPMathTag=nullptr)
Value * CreateIntCast(Value *V, Type *DestTy, bool isSigned, const Twine &Name="")
Value * CreateSExtOrTrunc(Value *V, Type *DestTy, const Twine &Name="")
Create a SExt or Trunc from the integer value V to DestTy.
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.
const DataLayout & getDataLayout() const
Get the data layout for the module's target platform.
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...
void push_back(const T &Elt)
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.
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
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.
bool isIntegerTy() const
True if this is an instance of IntegerType.
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.
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.
auto reverse(ContainerTy &&C)
DWARFExpression::Operation Op