Path: blob/main/contrib/llvm-project/llvm/lib/Target/DirectX/DXILLegalizePass.cpp
213799 views
//===- DXILLegalizePass.cpp - Legalizes llvm IR for DXIL ------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===---------------------------------------------------------------------===//78#include "DXILLegalizePass.h"9#include "DirectX.h"10#include "llvm/ADT/APInt.h"11#include "llvm/IR/Constants.h"12#include "llvm/IR/Function.h"13#include "llvm/IR/IRBuilder.h"14#include "llvm/IR/InstIterator.h"15#include "llvm/IR/Instruction.h"16#include "llvm/IR/Instructions.h"17#include "llvm/IR/Module.h"18#include "llvm/Pass.h"19#include "llvm/Transforms/Utils/BasicBlockUtils.h"20#include <functional>2122#define DEBUG_TYPE "dxil-legalize"2324using namespace llvm;2526static void legalizeFreeze(Instruction &I,27SmallVectorImpl<Instruction *> &ToRemove,28DenseMap<Value *, Value *>) {29auto *FI = dyn_cast<FreezeInst>(&I);30if (!FI)31return;3233FI->replaceAllUsesWith(FI->getOperand(0));34ToRemove.push_back(FI);35}3637static void fixI8UseChain(Instruction &I,38SmallVectorImpl<Instruction *> &ToRemove,39DenseMap<Value *, Value *> &ReplacedValues) {4041auto ProcessOperands = [&](SmallVector<Value *> &NewOperands) {42Type *InstrType = IntegerType::get(I.getContext(), 32);4344for (unsigned OpIdx = 0; OpIdx < I.getNumOperands(); ++OpIdx) {45Value *Op = I.getOperand(OpIdx);46if (ReplacedValues.count(Op) &&47ReplacedValues[Op]->getType()->isIntegerTy())48InstrType = ReplacedValues[Op]->getType();49}5051for (unsigned OpIdx = 0; OpIdx < I.getNumOperands(); ++OpIdx) {52Value *Op = I.getOperand(OpIdx);53if (ReplacedValues.count(Op))54NewOperands.push_back(ReplacedValues[Op]);55else if (auto *Imm = dyn_cast<ConstantInt>(Op)) {56APInt Value = Imm->getValue();57unsigned NewBitWidth = InstrType->getIntegerBitWidth();58// Note: options here are sext or sextOrTrunc.59// Since i8 isn't supported, we assume new values60// will always have a higher bitness.61assert(NewBitWidth > Value.getBitWidth() &&62"Replacement's BitWidth should be larger than Current.");63APInt NewValue = Value.sext(NewBitWidth);64NewOperands.push_back(ConstantInt::get(InstrType, NewValue));65} else {66assert(!Op->getType()->isIntegerTy(8));67NewOperands.push_back(Op);68}69}70};71IRBuilder<> Builder(&I);72if (auto *Trunc = dyn_cast<TruncInst>(&I)) {73if (Trunc->getDestTy()->isIntegerTy(8)) {74ReplacedValues[Trunc] = Trunc->getOperand(0);75ToRemove.push_back(Trunc);76return;77}78}7980if (auto *Store = dyn_cast<StoreInst>(&I)) {81if (!Store->getValueOperand()->getType()->isIntegerTy(8))82return;83SmallVector<Value *> NewOperands;84ProcessOperands(NewOperands);85Value *NewStore = Builder.CreateStore(NewOperands[0], NewOperands[1]);86ReplacedValues[Store] = NewStore;87ToRemove.push_back(Store);88return;89}9091if (auto *Load = dyn_cast<LoadInst>(&I);92Load && I.getType()->isIntegerTy(8)) {93SmallVector<Value *> NewOperands;94ProcessOperands(NewOperands);95Type *ElementType = NewOperands[0]->getType();96if (auto *AI = dyn_cast<AllocaInst>(NewOperands[0]))97ElementType = AI->getAllocatedType();98if (auto *GEP = dyn_cast<GetElementPtrInst>(NewOperands[0])) {99ElementType = GEP->getSourceElementType();100if (ElementType->isArrayTy())101ElementType = ElementType->getArrayElementType();102}103LoadInst *NewLoad = Builder.CreateLoad(ElementType, NewOperands[0]);104ReplacedValues[Load] = NewLoad;105ToRemove.push_back(Load);106return;107}108109if (auto *Load = dyn_cast<LoadInst>(&I);110Load && isa<ConstantExpr>(Load->getPointerOperand())) {111auto *CE = dyn_cast<ConstantExpr>(Load->getPointerOperand());112if (!(CE->getOpcode() == Instruction::GetElementPtr))113return;114auto *GEP = dyn_cast<GEPOperator>(CE);115if (!GEP->getSourceElementType()->isIntegerTy(8))116return;117118Type *ElementType = Load->getType();119ConstantInt *Offset = dyn_cast<ConstantInt>(GEP->getOperand(1));120uint32_t ByteOffset = Offset->getZExtValue();121uint32_t ElemSize = Load->getDataLayout().getTypeAllocSize(ElementType);122uint32_t Index = ByteOffset / ElemSize;123124Value *PtrOperand = GEP->getPointerOperand();125Type *GEPType = GEP->getPointerOperandType();126127if (auto *GV = dyn_cast<GlobalVariable>(PtrOperand))128GEPType = GV->getValueType();129if (auto *AI = dyn_cast<AllocaInst>(PtrOperand))130GEPType = AI->getAllocatedType();131132if (auto *ArrTy = dyn_cast<ArrayType>(GEPType))133GEPType = ArrTy;134else135GEPType = ArrayType::get(ElementType, 1); // its a scalar136137Value *NewGEP = Builder.CreateGEP(138GEPType, PtrOperand, {Builder.getInt32(0), Builder.getInt32(Index)},139GEP->getName(), GEP->getNoWrapFlags());140141LoadInst *NewLoad = Builder.CreateLoad(ElementType, NewGEP);142ReplacedValues[Load] = NewLoad;143Load->replaceAllUsesWith(NewLoad);144ToRemove.push_back(Load);145return;146}147148if (auto *BO = dyn_cast<BinaryOperator>(&I)) {149if (!I.getType()->isIntegerTy(8))150return;151SmallVector<Value *> NewOperands;152ProcessOperands(NewOperands);153Value *NewInst =154Builder.CreateBinOp(BO->getOpcode(), NewOperands[0], NewOperands[1]);155if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(&I)) {156auto *NewBO = dyn_cast<BinaryOperator>(NewInst);157if (NewBO && OBO->hasNoSignedWrap())158NewBO->setHasNoSignedWrap();159if (NewBO && OBO->hasNoUnsignedWrap())160NewBO->setHasNoUnsignedWrap();161}162ReplacedValues[BO] = NewInst;163ToRemove.push_back(BO);164return;165}166167if (auto *Sel = dyn_cast<SelectInst>(&I)) {168if (!I.getType()->isIntegerTy(8))169return;170SmallVector<Value *> NewOperands;171ProcessOperands(NewOperands);172Value *NewInst = Builder.CreateSelect(Sel->getCondition(), NewOperands[1],173NewOperands[2]);174ReplacedValues[Sel] = NewInst;175ToRemove.push_back(Sel);176return;177}178179if (auto *Cmp = dyn_cast<CmpInst>(&I)) {180if (!Cmp->getOperand(0)->getType()->isIntegerTy(8))181return;182SmallVector<Value *> NewOperands;183ProcessOperands(NewOperands);184Value *NewInst =185Builder.CreateCmp(Cmp->getPredicate(), NewOperands[0], NewOperands[1]);186Cmp->replaceAllUsesWith(NewInst);187ReplacedValues[Cmp] = NewInst;188ToRemove.push_back(Cmp);189return;190}191192if (auto *Cast = dyn_cast<CastInst>(&I)) {193if (!Cast->getSrcTy()->isIntegerTy(8))194return;195196ToRemove.push_back(Cast);197auto *Replacement = ReplacedValues[Cast->getOperand(0)];198if (Cast->getType() == Replacement->getType()) {199Cast->replaceAllUsesWith(Replacement);200return;201}202203Value *AdjustedCast = nullptr;204if (Cast->getOpcode() == Instruction::ZExt)205AdjustedCast = Builder.CreateZExtOrTrunc(Replacement, Cast->getType());206if (Cast->getOpcode() == Instruction::SExt)207AdjustedCast = Builder.CreateSExtOrTrunc(Replacement, Cast->getType());208209if (AdjustedCast)210Cast->replaceAllUsesWith(AdjustedCast);211}212if (auto *GEP = dyn_cast<GetElementPtrInst>(&I)) {213if (!GEP->getType()->isPointerTy() ||214!GEP->getSourceElementType()->isIntegerTy(8))215return;216217Value *BasePtr = GEP->getPointerOperand();218if (ReplacedValues.count(BasePtr))219BasePtr = ReplacedValues[BasePtr];220221Type *ElementType = BasePtr->getType();222223if (auto *AI = dyn_cast<AllocaInst>(BasePtr))224ElementType = AI->getAllocatedType();225if (auto *GV = dyn_cast<GlobalVariable>(BasePtr))226ElementType = GV->getValueType();227228Type *GEPType = ElementType;229if (auto *ArrTy = dyn_cast<ArrayType>(ElementType))230ElementType = ArrTy->getArrayElementType();231else232GEPType = ArrayType::get(ElementType, 1); // its a scalar233234ConstantInt *Offset = dyn_cast<ConstantInt>(GEP->getOperand(1));235// Note: i8 to i32 offset conversion without emitting IR requires constant236// ints. Since offset conversion is common, we can safely assume Offset is237// always a ConstantInt, so no need to have a conditional bail out on238// nullptr, instead assert this is the case.239assert(Offset && "Offset is expected to be a ConstantInt");240uint32_t ByteOffset = Offset->getZExtValue();241uint32_t ElemSize = GEP->getDataLayout().getTypeAllocSize(ElementType);242assert(ElemSize > 0 && "ElementSize must be set");243uint32_t Index = ByteOffset / ElemSize;244Value *NewGEP = Builder.CreateGEP(245GEPType, BasePtr, {Builder.getInt32(0), Builder.getInt32(Index)},246GEP->getName(), GEP->getNoWrapFlags());247ReplacedValues[GEP] = NewGEP;248GEP->replaceAllUsesWith(NewGEP);249ToRemove.push_back(GEP);250}251}252253static void upcastI8AllocasAndUses(Instruction &I,254SmallVectorImpl<Instruction *> &ToRemove,255DenseMap<Value *, Value *> &ReplacedValues) {256auto *AI = dyn_cast<AllocaInst>(&I);257if (!AI || !AI->getAllocatedType()->isIntegerTy(8))258return;259260Type *SmallestType = nullptr;261262auto ProcessLoad = [&](LoadInst *Load) {263for (User *LU : Load->users()) {264Type *Ty = nullptr;265if (CastInst *Cast = dyn_cast<CastInst>(LU))266Ty = Cast->getType();267else if (CallInst *CI = dyn_cast<CallInst>(LU)) {268if (CI->getIntrinsicID() == Intrinsic::memset)269Ty = Type::getInt32Ty(CI->getContext());270}271272if (!Ty)273continue;274275if (!SmallestType ||276Ty->getPrimitiveSizeInBits() < SmallestType->getPrimitiveSizeInBits())277SmallestType = Ty;278}279};280281for (User *U : AI->users()) {282if (auto *Load = dyn_cast<LoadInst>(U))283ProcessLoad(Load);284else if (auto *GEP = dyn_cast<GetElementPtrInst>(U)) {285for (User *GU : GEP->users()) {286if (auto *Load = dyn_cast<LoadInst>(GU))287ProcessLoad(Load);288}289}290}291292if (!SmallestType)293return; // no valid casts found294295// Replace alloca296IRBuilder<> Builder(AI);297auto *NewAlloca = Builder.CreateAlloca(SmallestType);298ReplacedValues[AI] = NewAlloca;299ToRemove.push_back(AI);300}301302static void303downcastI64toI32InsertExtractElements(Instruction &I,304SmallVectorImpl<Instruction *> &ToRemove,305DenseMap<Value *, Value *> &) {306307if (auto *Extract = dyn_cast<ExtractElementInst>(&I)) {308Value *Idx = Extract->getIndexOperand();309auto *CI = dyn_cast<ConstantInt>(Idx);310if (CI && CI->getBitWidth() == 64) {311IRBuilder<> Builder(Extract);312int64_t IndexValue = CI->getSExtValue();313auto *Idx32 =314ConstantInt::get(Type::getInt32Ty(I.getContext()), IndexValue);315Value *NewExtract = Builder.CreateExtractElement(316Extract->getVectorOperand(), Idx32, Extract->getName());317318Extract->replaceAllUsesWith(NewExtract);319ToRemove.push_back(Extract);320}321}322323if (auto *Insert = dyn_cast<InsertElementInst>(&I)) {324Value *Idx = Insert->getOperand(2);325auto *CI = dyn_cast<ConstantInt>(Idx);326if (CI && CI->getBitWidth() == 64) {327int64_t IndexValue = CI->getSExtValue();328auto *Idx32 =329ConstantInt::get(Type::getInt32Ty(I.getContext()), IndexValue);330IRBuilder<> Builder(Insert);331Value *Insert32Index = Builder.CreateInsertElement(332Insert->getOperand(0), Insert->getOperand(1), Idx32,333Insert->getName());334335Insert->replaceAllUsesWith(Insert32Index);336ToRemove.push_back(Insert);337}338}339}340341static void emitMemcpyExpansion(IRBuilder<> &Builder, Value *Dst, Value *Src,342ConstantInt *Length) {343344uint64_t ByteLength = Length->getZExtValue();345// If length to copy is zero, no memcpy is needed.346if (ByteLength == 0)347return;348349LLVMContext &Ctx = Builder.getContext();350const DataLayout &DL = Builder.GetInsertBlock()->getModule()->getDataLayout();351352auto GetArrTyFromVal = [](Value *Val) -> ArrayType * {353assert(isa<AllocaInst>(Val) ||354isa<GlobalVariable>(Val) &&355"Expected Val to be an Alloca or Global Variable");356if (auto *Alloca = dyn_cast<AllocaInst>(Val))357return dyn_cast<ArrayType>(Alloca->getAllocatedType());358if (auto *GlobalVar = dyn_cast<GlobalVariable>(Val))359return dyn_cast<ArrayType>(GlobalVar->getValueType());360return nullptr;361};362363ArrayType *DstArrTy = GetArrTyFromVal(Dst);364assert(DstArrTy && "Expected Dst of memcpy to be a Pointer to an Array Type");365if (auto *DstGlobalVar = dyn_cast<GlobalVariable>(Dst))366assert(!DstGlobalVar->isConstant() &&367"The Dst of memcpy must not be a constant Global Variable");368[[maybe_unused]] ArrayType *SrcArrTy = GetArrTyFromVal(Src);369assert(SrcArrTy && "Expected Src of memcpy to be a Pointer to an Array Type");370371Type *DstElemTy = DstArrTy->getElementType();372uint64_t DstElemByteSize = DL.getTypeStoreSize(DstElemTy);373assert(DstElemByteSize > 0 && "Dst element type store size must be set");374Type *SrcElemTy = SrcArrTy->getElementType();375[[maybe_unused]] uint64_t SrcElemByteSize = DL.getTypeStoreSize(SrcElemTy);376assert(SrcElemByteSize > 0 && "Src element type store size must be set");377378// This assumption simplifies implementation and covers currently-known379// use-cases for DXIL. It may be relaxed in the future if required.380assert(DstElemTy == SrcElemTy &&381"The element types of Src and Dst arrays must match");382383[[maybe_unused]] uint64_t DstArrNumElems = DstArrTy->getArrayNumElements();384assert(DstElemByteSize * DstArrNumElems >= ByteLength &&385"Dst array size must be at least as large as the memcpy length");386[[maybe_unused]] uint64_t SrcArrNumElems = SrcArrTy->getArrayNumElements();387assert(SrcElemByteSize * SrcArrNumElems >= ByteLength &&388"Src array size must be at least as large as the memcpy length");389390uint64_t NumElemsToCopy = ByteLength / DstElemByteSize;391assert(ByteLength % DstElemByteSize == 0 &&392"memcpy length must be divisible by array element type");393for (uint64_t I = 0; I < NumElemsToCopy; ++I) {394Value *Offset = ConstantInt::get(Type::getInt32Ty(Ctx), I);395Value *SrcPtr = Builder.CreateInBoundsGEP(SrcElemTy, Src, Offset, "gep");396Value *SrcVal = Builder.CreateLoad(SrcElemTy, SrcPtr);397Value *DstPtr = Builder.CreateInBoundsGEP(DstElemTy, Dst, Offset, "gep");398Builder.CreateStore(SrcVal, DstPtr);399}400}401402static void emitMemsetExpansion(IRBuilder<> &Builder, Value *Dst, Value *Val,403ConstantInt *SizeCI,404DenseMap<Value *, Value *> &ReplacedValues) {405LLVMContext &Ctx = Builder.getContext();406[[maybe_unused]] const DataLayout &DL =407Builder.GetInsertBlock()->getModule()->getDataLayout();408[[maybe_unused]] uint64_t OrigSize = SizeCI->getZExtValue();409410AllocaInst *Alloca = dyn_cast<AllocaInst>(Dst);411412assert(Alloca && "Expected memset on an Alloca");413assert(OrigSize == Alloca->getAllocationSize(DL)->getFixedValue() &&414"Expected for memset size to match DataLayout size");415416Type *AllocatedTy = Alloca->getAllocatedType();417ArrayType *ArrTy = dyn_cast<ArrayType>(AllocatedTy);418assert(ArrTy && "Expected Alloca for an Array Type");419420Type *ElemTy = ArrTy->getElementType();421uint64_t Size = ArrTy->getArrayNumElements();422423[[maybe_unused]] uint64_t ElemSize = DL.getTypeStoreSize(ElemTy);424425assert(ElemSize > 0 && "Size must be set");426assert(OrigSize == ElemSize * Size && "Size in bytes must match");427428Value *TypedVal = Val;429430if (Val->getType() != ElemTy) {431if (ReplacedValues[Val]) {432// Note for i8 replacements if we know them we should use them.433// Further if this is a constant ReplacedValues will return null434// so we will stick to TypedVal = Val435TypedVal = ReplacedValues[Val];436437} else {438// This case Val is a ConstantInt so the cast folds away.439// However if we don't do the cast the store below ends up being440// an i8.441TypedVal = Builder.CreateIntCast(Val, ElemTy, false);442}443}444445for (uint64_t I = 0; I < Size; ++I) {446Value *Offset = ConstantInt::get(Type::getInt32Ty(Ctx), I);447Value *Ptr = Builder.CreateGEP(ElemTy, Dst, Offset, "gep");448Builder.CreateStore(TypedVal, Ptr);449}450}451452// Expands the instruction `I` into corresponding loads and stores if it is a453// memcpy call. In that case, the call instruction is added to the `ToRemove`454// vector. `ReplacedValues` is unused.455static void legalizeMemCpy(Instruction &I,456SmallVectorImpl<Instruction *> &ToRemove,457DenseMap<Value *, Value *> &ReplacedValues) {458459CallInst *CI = dyn_cast<CallInst>(&I);460if (!CI)461return;462463Intrinsic::ID ID = CI->getIntrinsicID();464if (ID != Intrinsic::memcpy)465return;466467IRBuilder<> Builder(&I);468Value *Dst = CI->getArgOperand(0);469Value *Src = CI->getArgOperand(1);470ConstantInt *Length = dyn_cast<ConstantInt>(CI->getArgOperand(2));471assert(Length && "Expected Length to be a ConstantInt");472[[maybe_unused]] ConstantInt *IsVolatile =473dyn_cast<ConstantInt>(CI->getArgOperand(3));474assert(IsVolatile && "Expected IsVolatile to be a ConstantInt");475assert(IsVolatile->getZExtValue() == 0 && "Expected IsVolatile to be false");476emitMemcpyExpansion(Builder, Dst, Src, Length);477ToRemove.push_back(CI);478}479480static void removeMemSet(Instruction &I,481SmallVectorImpl<Instruction *> &ToRemove,482DenseMap<Value *, Value *> &ReplacedValues) {483484CallInst *CI = dyn_cast<CallInst>(&I);485if (!CI)486return;487488Intrinsic::ID ID = CI->getIntrinsicID();489if (ID != Intrinsic::memset)490return;491492IRBuilder<> Builder(&I);493Value *Dst = CI->getArgOperand(0);494Value *Val = CI->getArgOperand(1);495ConstantInt *Size = dyn_cast<ConstantInt>(CI->getArgOperand(2));496assert(Size && "Expected Size to be a ConstantInt");497emitMemsetExpansion(Builder, Dst, Val, Size, ReplacedValues);498ToRemove.push_back(CI);499}500501static void updateFnegToFsub(Instruction &I,502SmallVectorImpl<Instruction *> &ToRemove,503DenseMap<Value *, Value *> &) {504const Intrinsic::ID ID = I.getOpcode();505if (ID != Instruction::FNeg)506return;507508IRBuilder<> Builder(&I);509Value *In = I.getOperand(0);510Value *Zero = ConstantFP::get(In->getType(), -0.0);511I.replaceAllUsesWith(Builder.CreateFSub(Zero, In));512ToRemove.push_back(&I);513}514515static void516legalizeGetHighLowi64Bytes(Instruction &I,517SmallVectorImpl<Instruction *> &ToRemove,518DenseMap<Value *, Value *> &ReplacedValues) {519if (auto *BitCast = dyn_cast<BitCastInst>(&I)) {520if (BitCast->getDestTy() ==521FixedVectorType::get(Type::getInt32Ty(I.getContext()), 2) &&522BitCast->getSrcTy()->isIntegerTy(64)) {523ToRemove.push_back(BitCast);524ReplacedValues[BitCast] = BitCast->getOperand(0);525return;526}527}528529if (auto *Extract = dyn_cast<ExtractElementInst>(&I)) {530if (!dyn_cast<BitCastInst>(Extract->getVectorOperand()))531return;532auto *VecTy = dyn_cast<FixedVectorType>(Extract->getVectorOperandType());533if (VecTy && VecTy->getElementType()->isIntegerTy(32) &&534VecTy->getNumElements() == 2) {535if (auto *Index = dyn_cast<ConstantInt>(Extract->getIndexOperand())) {536unsigned Idx = Index->getZExtValue();537IRBuilder<> Builder(&I);538539auto *Replacement = ReplacedValues[Extract->getVectorOperand()];540assert(Replacement && "The BitCast replacement should have been set "541"before working on ExtractElementInst.");542if (Idx == 0) {543Value *LowBytes = Builder.CreateTrunc(544Replacement, Type::getInt32Ty(I.getContext()));545ReplacedValues[Extract] = LowBytes;546} else {547assert(Idx == 1);548Value *LogicalShiftRight = Builder.CreateLShr(549Replacement,550ConstantInt::get(551Replacement->getType(),552APInt(Replacement->getType()->getIntegerBitWidth(), 32)));553Value *HighBytes = Builder.CreateTrunc(554LogicalShiftRight, Type::getInt32Ty(I.getContext()));555ReplacedValues[Extract] = HighBytes;556}557ToRemove.push_back(Extract);558Extract->replaceAllUsesWith(ReplacedValues[Extract]);559}560}561}562}563564namespace {565class DXILLegalizationPipeline {566567public:568DXILLegalizationPipeline() { initializeLegalizationPipeline(); }569570bool runLegalizationPipeline(Function &F) {571bool MadeChange = false;572SmallVector<Instruction *> ToRemove;573DenseMap<Value *, Value *> ReplacedValues;574for (int Stage = 0; Stage < NumStages; ++Stage) {575ToRemove.clear();576ReplacedValues.clear();577for (auto &I : instructions(F)) {578for (auto &LegalizationFn : LegalizationPipeline[Stage])579LegalizationFn(I, ToRemove, ReplacedValues);580}581582for (auto *Inst : reverse(ToRemove))583Inst->eraseFromParent();584585MadeChange |= !ToRemove.empty();586}587return MadeChange;588}589590private:591enum LegalizationStage { Stage1 = 0, Stage2 = 1, NumStages };592593using LegalizationFnTy =594std::function<void(Instruction &, SmallVectorImpl<Instruction *> &,595DenseMap<Value *, Value *> &)>;596597SmallVector<LegalizationFnTy> LegalizationPipeline[NumStages];598599void initializeLegalizationPipeline() {600LegalizationPipeline[Stage1].push_back(upcastI8AllocasAndUses);601LegalizationPipeline[Stage1].push_back(fixI8UseChain);602LegalizationPipeline[Stage1].push_back(legalizeGetHighLowi64Bytes);603LegalizationPipeline[Stage1].push_back(legalizeFreeze);604LegalizationPipeline[Stage1].push_back(legalizeMemCpy);605LegalizationPipeline[Stage1].push_back(removeMemSet);606LegalizationPipeline[Stage1].push_back(updateFnegToFsub);607// Note: legalizeGetHighLowi64Bytes and608// downcastI64toI32InsertExtractElements both modify extractelement, so they609// must run staggered stages. legalizeGetHighLowi64Bytes runs first b\c it610// removes extractelements, reducing the number that611// downcastI64toI32InsertExtractElements needs to handle.612LegalizationPipeline[Stage2].push_back(613downcastI64toI32InsertExtractElements);614}615};616617class DXILLegalizeLegacy : public FunctionPass {618619public:620bool runOnFunction(Function &F) override;621DXILLegalizeLegacy() : FunctionPass(ID) {}622623static char ID; // Pass identification.624};625} // namespace626627PreservedAnalyses DXILLegalizePass::run(Function &F,628FunctionAnalysisManager &FAM) {629DXILLegalizationPipeline DXLegalize;630bool MadeChanges = DXLegalize.runLegalizationPipeline(F);631if (!MadeChanges)632return PreservedAnalyses::all();633PreservedAnalyses PA;634return PA;635}636637bool DXILLegalizeLegacy::runOnFunction(Function &F) {638DXILLegalizationPipeline DXLegalize;639return DXLegalize.runLegalizationPipeline(F);640}641642char DXILLegalizeLegacy::ID = 0;643644INITIALIZE_PASS_BEGIN(DXILLegalizeLegacy, DEBUG_TYPE, "DXIL Legalizer", false,645false)646INITIALIZE_PASS_END(DXILLegalizeLegacy, DEBUG_TYPE, "DXIL Legalizer", false,647false)648649FunctionPass *llvm::createDXILLegalizeLegacyPass() {650return new DXILLegalizeLegacy();651}652653654