xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/DirectX/DXILPrepare.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
181ad6265SDimitry Andric //===- DXILPrepare.cpp - Prepare LLVM Module for DXIL encoding ------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric ///
981ad6265SDimitry Andric /// \file This file contains pases and utilities to convert a modern LLVM
1081ad6265SDimitry Andric /// module into a module compatible with the LLVM 3.7-based DirectX Intermediate
1181ad6265SDimitry Andric /// Language (DXIL).
1281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1381ad6265SDimitry Andric 
1481ad6265SDimitry Andric #include "DirectX.h"
15*bdd1243dSDimitry Andric #include "DirectXIRPasses/PointerTypeAnalysis.h"
1681ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h"
1781ad6265SDimitry Andric #include "llvm/ADT/SmallVector.h"
1881ad6265SDimitry Andric #include "llvm/CodeGen/Passes.h"
1981ad6265SDimitry Andric #include "llvm/IR/IRBuilder.h"
2081ad6265SDimitry Andric #include "llvm/IR/Instruction.h"
2181ad6265SDimitry Andric #include "llvm/IR/Module.h"
2281ad6265SDimitry Andric #include "llvm/InitializePasses.h"
2381ad6265SDimitry Andric #include "llvm/Pass.h"
2481ad6265SDimitry Andric #include "llvm/Support/Compiler.h"
2581ad6265SDimitry Andric 
2681ad6265SDimitry Andric #define DEBUG_TYPE "dxil-prepare"
2781ad6265SDimitry Andric 
2881ad6265SDimitry Andric using namespace llvm;
2981ad6265SDimitry Andric using namespace llvm::dxil;
3081ad6265SDimitry Andric 
3181ad6265SDimitry Andric namespace {
3281ad6265SDimitry Andric 
3381ad6265SDimitry Andric constexpr bool isValidForDXIL(Attribute::AttrKind Attr) {
3481ad6265SDimitry Andric   return is_contained({Attribute::Alignment,
3581ad6265SDimitry Andric                        Attribute::AlwaysInline,
3681ad6265SDimitry Andric                        Attribute::Builtin,
3781ad6265SDimitry Andric                        Attribute::ByVal,
3881ad6265SDimitry Andric                        Attribute::InAlloca,
3981ad6265SDimitry Andric                        Attribute::Cold,
4081ad6265SDimitry Andric                        Attribute::Convergent,
4181ad6265SDimitry Andric                        Attribute::InlineHint,
4281ad6265SDimitry Andric                        Attribute::InReg,
4381ad6265SDimitry Andric                        Attribute::JumpTable,
4481ad6265SDimitry Andric                        Attribute::MinSize,
4581ad6265SDimitry Andric                        Attribute::Naked,
4681ad6265SDimitry Andric                        Attribute::Nest,
4781ad6265SDimitry Andric                        Attribute::NoAlias,
4881ad6265SDimitry Andric                        Attribute::NoBuiltin,
4981ad6265SDimitry Andric                        Attribute::NoCapture,
5081ad6265SDimitry Andric                        Attribute::NoDuplicate,
5181ad6265SDimitry Andric                        Attribute::NoImplicitFloat,
5281ad6265SDimitry Andric                        Attribute::NoInline,
5381ad6265SDimitry Andric                        Attribute::NonLazyBind,
5481ad6265SDimitry Andric                        Attribute::NonNull,
5581ad6265SDimitry Andric                        Attribute::Dereferenceable,
5681ad6265SDimitry Andric                        Attribute::DereferenceableOrNull,
57*bdd1243dSDimitry Andric                        Attribute::Memory,
5881ad6265SDimitry Andric                        Attribute::NoRedZone,
5981ad6265SDimitry Andric                        Attribute::NoReturn,
6081ad6265SDimitry Andric                        Attribute::NoUnwind,
6181ad6265SDimitry Andric                        Attribute::OptimizeForSize,
6281ad6265SDimitry Andric                        Attribute::OptimizeNone,
6381ad6265SDimitry Andric                        Attribute::ReadNone,
6481ad6265SDimitry Andric                        Attribute::ReadOnly,
6581ad6265SDimitry Andric                        Attribute::Returned,
6681ad6265SDimitry Andric                        Attribute::ReturnsTwice,
6781ad6265SDimitry Andric                        Attribute::SExt,
6881ad6265SDimitry Andric                        Attribute::StackAlignment,
6981ad6265SDimitry Andric                        Attribute::StackProtect,
7081ad6265SDimitry Andric                        Attribute::StackProtectReq,
7181ad6265SDimitry Andric                        Attribute::StackProtectStrong,
7281ad6265SDimitry Andric                        Attribute::SafeStack,
7381ad6265SDimitry Andric                        Attribute::StructRet,
7481ad6265SDimitry Andric                        Attribute::SanitizeAddress,
7581ad6265SDimitry Andric                        Attribute::SanitizeThread,
7681ad6265SDimitry Andric                        Attribute::SanitizeMemory,
7781ad6265SDimitry Andric                        Attribute::UWTable,
7881ad6265SDimitry Andric                        Attribute::ZExt},
7981ad6265SDimitry Andric                       Attr);
8081ad6265SDimitry Andric }
8181ad6265SDimitry Andric 
8281ad6265SDimitry Andric class DXILPrepareModule : public ModulePass {
8381ad6265SDimitry Andric 
8481ad6265SDimitry Andric   static Value *maybeGenerateBitcast(IRBuilder<> &Builder,
8581ad6265SDimitry Andric                                      PointerTypeMap &PointerTypes,
8681ad6265SDimitry Andric                                      Instruction &Inst, Value *Operand,
8781ad6265SDimitry Andric                                      Type *Ty) {
8881ad6265SDimitry Andric     // Omit bitcasts if the incoming value matches the instruction type.
8981ad6265SDimitry Andric     auto It = PointerTypes.find(Operand);
9081ad6265SDimitry Andric     if (It != PointerTypes.end())
9181ad6265SDimitry Andric       if (cast<TypedPointerType>(It->second)->getElementType() == Ty)
9281ad6265SDimitry Andric         return nullptr;
9381ad6265SDimitry Andric     // Insert bitcasts where we are removing the instruction.
9481ad6265SDimitry Andric     Builder.SetInsertPoint(&Inst);
9581ad6265SDimitry Andric     // This code only gets hit in opaque-pointer mode, so the type of the
9681ad6265SDimitry Andric     // pointer doesn't matter.
9781ad6265SDimitry Andric     PointerType *PtrTy = cast<PointerType>(Operand->getType());
9881ad6265SDimitry Andric     return Builder.Insert(
9981ad6265SDimitry Andric         CastInst::Create(Instruction::BitCast, Operand,
10081ad6265SDimitry Andric                          Builder.getInt8PtrTy(PtrTy->getAddressSpace())));
10181ad6265SDimitry Andric   }
10281ad6265SDimitry Andric 
10381ad6265SDimitry Andric public:
10481ad6265SDimitry Andric   bool runOnModule(Module &M) override {
10581ad6265SDimitry Andric     PointerTypeMap PointerTypes = PointerTypeAnalysis::run(M);
10681ad6265SDimitry Andric     AttributeMask AttrMask;
10781ad6265SDimitry Andric     for (Attribute::AttrKind I = Attribute::None; I != Attribute::EndAttrKinds;
10881ad6265SDimitry Andric          I = Attribute::AttrKind(I + 1)) {
10981ad6265SDimitry Andric       if (!isValidForDXIL(I))
11081ad6265SDimitry Andric         AttrMask.addAttribute(I);
11181ad6265SDimitry Andric     }
11281ad6265SDimitry Andric     for (auto &F : M.functions()) {
11381ad6265SDimitry Andric       F.removeFnAttrs(AttrMask);
11481ad6265SDimitry Andric       F.removeRetAttrs(AttrMask);
11581ad6265SDimitry Andric       for (size_t Idx = 0, End = F.arg_size(); Idx < End; ++Idx)
11681ad6265SDimitry Andric         F.removeParamAttrs(Idx, AttrMask);
11781ad6265SDimitry Andric 
11881ad6265SDimitry Andric       for (auto &BB : F) {
11981ad6265SDimitry Andric         IRBuilder<> Builder(&BB);
12081ad6265SDimitry Andric         for (auto &I : make_early_inc_range(BB)) {
12181ad6265SDimitry Andric           if (I.getOpcode() == Instruction::FNeg) {
12281ad6265SDimitry Andric             Builder.SetInsertPoint(&I);
12381ad6265SDimitry Andric             Value *In = I.getOperand(0);
12481ad6265SDimitry Andric             Value *Zero = ConstantFP::get(In->getType(), -0.0);
12581ad6265SDimitry Andric             I.replaceAllUsesWith(Builder.CreateFSub(Zero, In));
12681ad6265SDimitry Andric             I.eraseFromParent();
12781ad6265SDimitry Andric             continue;
12881ad6265SDimitry Andric           }
12981ad6265SDimitry Andric           // Only insert bitcasts if the IR is using opaque pointers.
13081ad6265SDimitry Andric           if (M.getContext().supportsTypedPointers())
13181ad6265SDimitry Andric             continue;
13281ad6265SDimitry Andric 
13381ad6265SDimitry Andric           // Emtting NoOp bitcast instructions allows the ValueEnumerator to be
13481ad6265SDimitry Andric           // unmodified as it reserves instruction IDs during contruction.
13581ad6265SDimitry Andric           if (auto LI = dyn_cast<LoadInst>(&I)) {
13681ad6265SDimitry Andric             if (Value *NoOpBitcast = maybeGenerateBitcast(
13781ad6265SDimitry Andric                     Builder, PointerTypes, I, LI->getPointerOperand(),
13881ad6265SDimitry Andric                     LI->getType())) {
13981ad6265SDimitry Andric               LI->replaceAllUsesWith(
14081ad6265SDimitry Andric                   Builder.CreateLoad(LI->getType(), NoOpBitcast));
14181ad6265SDimitry Andric               LI->eraseFromParent();
14281ad6265SDimitry Andric             }
14381ad6265SDimitry Andric             continue;
14481ad6265SDimitry Andric           }
14581ad6265SDimitry Andric           if (auto SI = dyn_cast<StoreInst>(&I)) {
14681ad6265SDimitry Andric             if (Value *NoOpBitcast = maybeGenerateBitcast(
14781ad6265SDimitry Andric                     Builder, PointerTypes, I, SI->getPointerOperand(),
14881ad6265SDimitry Andric                     SI->getValueOperand()->getType())) {
14981ad6265SDimitry Andric 
15081ad6265SDimitry Andric               SI->replaceAllUsesWith(
15181ad6265SDimitry Andric                   Builder.CreateStore(SI->getValueOperand(), NoOpBitcast));
15281ad6265SDimitry Andric               SI->eraseFromParent();
15381ad6265SDimitry Andric             }
15481ad6265SDimitry Andric             continue;
15581ad6265SDimitry Andric           }
15681ad6265SDimitry Andric           if (auto GEP = dyn_cast<GetElementPtrInst>(&I)) {
15781ad6265SDimitry Andric             if (Value *NoOpBitcast = maybeGenerateBitcast(
15881ad6265SDimitry Andric                     Builder, PointerTypes, I, GEP->getPointerOperand(),
15981ad6265SDimitry Andric                     GEP->getResultElementType()))
16081ad6265SDimitry Andric               GEP->setOperand(0, NoOpBitcast);
16181ad6265SDimitry Andric             continue;
16281ad6265SDimitry Andric           }
163*bdd1243dSDimitry Andric           if (auto *CB = dyn_cast<CallBase>(&I)) {
164*bdd1243dSDimitry Andric             CB->removeFnAttrs(AttrMask);
165*bdd1243dSDimitry Andric             CB->removeRetAttrs(AttrMask);
166*bdd1243dSDimitry Andric             for (size_t Idx = 0, End = CB->arg_size(); Idx < End; ++Idx)
167*bdd1243dSDimitry Andric               CB->removeParamAttrs(Idx, AttrMask);
168*bdd1243dSDimitry Andric             continue;
169*bdd1243dSDimitry Andric           }
17081ad6265SDimitry Andric         }
17181ad6265SDimitry Andric       }
17281ad6265SDimitry Andric     }
17381ad6265SDimitry Andric     return true;
17481ad6265SDimitry Andric   }
17581ad6265SDimitry Andric 
17681ad6265SDimitry Andric   DXILPrepareModule() : ModulePass(ID) {}
17781ad6265SDimitry Andric 
17881ad6265SDimitry Andric   static char ID; // Pass identification.
17981ad6265SDimitry Andric };
18081ad6265SDimitry Andric char DXILPrepareModule::ID = 0;
18181ad6265SDimitry Andric 
18281ad6265SDimitry Andric } // end anonymous namespace
18381ad6265SDimitry Andric 
18481ad6265SDimitry Andric INITIALIZE_PASS_BEGIN(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module",
18581ad6265SDimitry Andric                       false, false)
18681ad6265SDimitry Andric INITIALIZE_PASS_END(DXILPrepareModule, DEBUG_TYPE, "DXIL Prepare Module", false,
18781ad6265SDimitry Andric                     false)
18881ad6265SDimitry Andric 
18981ad6265SDimitry Andric ModulePass *llvm::createDXILPrepareModulePass() {
19081ad6265SDimitry Andric   return new DXILPrepareModule();
19181ad6265SDimitry Andric }
192