xref: /freebsd/contrib/llvm-project/llvm/lib/Target/DirectX/DXILOpLowering.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //===- DXILOpLower.cpp - Lowering LLVM intrinsic to DIXLOp function -------===//
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 passes and utilities to lower llvm intrinsic call
1081ad6265SDimitry Andric /// to DXILOp function call.
1181ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1281ad6265SDimitry Andric 
1381ad6265SDimitry Andric #include "DXILConstants.h"
14*0fca6ea1SDimitry Andric #include "DXILIntrinsicExpansion.h"
15972a253aSDimitry Andric #include "DXILOpBuilder.h"
1681ad6265SDimitry Andric #include "DirectX.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/Intrinsics.h"
2281ad6265SDimitry Andric #include "llvm/IR/IntrinsicsDirectX.h"
2381ad6265SDimitry Andric #include "llvm/IR/Module.h"
2481ad6265SDimitry Andric #include "llvm/IR/PassManager.h"
2581ad6265SDimitry Andric #include "llvm/Pass.h"
2681ad6265SDimitry Andric #include "llvm/Support/ErrorHandling.h"
2781ad6265SDimitry Andric 
2881ad6265SDimitry Andric #define DEBUG_TYPE "dxil-op-lower"
2981ad6265SDimitry Andric 
3081ad6265SDimitry Andric using namespace llvm;
31bdd1243dSDimitry Andric using namespace llvm::dxil;
3281ad6265SDimitry Andric 
isVectorArgExpansion(Function & F)33*0fca6ea1SDimitry Andric static bool isVectorArgExpansion(Function &F) {
34*0fca6ea1SDimitry Andric   switch (F.getIntrinsicID()) {
35*0fca6ea1SDimitry Andric   case Intrinsic::dx_dot2:
36*0fca6ea1SDimitry Andric   case Intrinsic::dx_dot3:
37*0fca6ea1SDimitry Andric   case Intrinsic::dx_dot4:
38*0fca6ea1SDimitry Andric     return true;
39*0fca6ea1SDimitry Andric   }
40*0fca6ea1SDimitry Andric   return false;
41*0fca6ea1SDimitry Andric }
42*0fca6ea1SDimitry Andric 
populateOperands(Value * Arg,IRBuilder<> & Builder)43*0fca6ea1SDimitry Andric static SmallVector<Value *> populateOperands(Value *Arg, IRBuilder<> &Builder) {
44*0fca6ea1SDimitry Andric   SmallVector<Value *> ExtractedElements;
45*0fca6ea1SDimitry Andric   auto *VecArg = dyn_cast<FixedVectorType>(Arg->getType());
46*0fca6ea1SDimitry Andric   for (unsigned I = 0; I < VecArg->getNumElements(); ++I) {
47*0fca6ea1SDimitry Andric     Value *Index = ConstantInt::get(Type::getInt32Ty(Arg->getContext()), I);
48*0fca6ea1SDimitry Andric     Value *ExtractedElement = Builder.CreateExtractElement(Arg, Index);
49*0fca6ea1SDimitry Andric     ExtractedElements.push_back(ExtractedElement);
50*0fca6ea1SDimitry Andric   }
51*0fca6ea1SDimitry Andric   return ExtractedElements;
52*0fca6ea1SDimitry Andric }
53*0fca6ea1SDimitry Andric 
argVectorFlatten(CallInst * Orig,IRBuilder<> & Builder)54*0fca6ea1SDimitry Andric static SmallVector<Value *> argVectorFlatten(CallInst *Orig,
55*0fca6ea1SDimitry Andric                                              IRBuilder<> &Builder) {
56*0fca6ea1SDimitry Andric   // Note: arg[NumOperands-1] is a pointer and is not needed by our flattening.
57*0fca6ea1SDimitry Andric   unsigned NumOperands = Orig->getNumOperands() - 1;
58*0fca6ea1SDimitry Andric   assert(NumOperands > 0);
59*0fca6ea1SDimitry Andric   Value *Arg0 = Orig->getOperand(0);
60*0fca6ea1SDimitry Andric   [[maybe_unused]] auto *VecArg0 = dyn_cast<FixedVectorType>(Arg0->getType());
61*0fca6ea1SDimitry Andric   assert(VecArg0);
62*0fca6ea1SDimitry Andric   SmallVector<Value *> NewOperands = populateOperands(Arg0, Builder);
63*0fca6ea1SDimitry Andric   for (unsigned I = 1; I < NumOperands; ++I) {
64*0fca6ea1SDimitry Andric     Value *Arg = Orig->getOperand(I);
65*0fca6ea1SDimitry Andric     [[maybe_unused]] auto *VecArg = dyn_cast<FixedVectorType>(Arg->getType());
66*0fca6ea1SDimitry Andric     assert(VecArg);
67*0fca6ea1SDimitry Andric     assert(VecArg0->getElementType() == VecArg->getElementType());
68*0fca6ea1SDimitry Andric     assert(VecArg0->getNumElements() == VecArg->getNumElements());
69*0fca6ea1SDimitry Andric     auto NextOperandList = populateOperands(Arg, Builder);
70*0fca6ea1SDimitry Andric     NewOperands.append(NextOperandList.begin(), NextOperandList.end());
71*0fca6ea1SDimitry Andric   }
72*0fca6ea1SDimitry Andric   return NewOperands;
73*0fca6ea1SDimitry Andric }
74*0fca6ea1SDimitry Andric 
lowerIntrinsic(dxil::OpCode DXILOp,Function & F,Module & M)75bdd1243dSDimitry Andric static void lowerIntrinsic(dxil::OpCode DXILOp, Function &F, Module &M) {
7681ad6265SDimitry Andric   IRBuilder<> B(M.getContext());
77972a253aSDimitry Andric   DXILOpBuilder DXILB(M, B);
78*0fca6ea1SDimitry Andric   Type *OverloadTy = DXILB.getOverloadTy(DXILOp, F.getFunctionType());
7981ad6265SDimitry Andric   for (User *U : make_early_inc_range(F.users())) {
8081ad6265SDimitry Andric     CallInst *CI = dyn_cast<CallInst>(U);
8181ad6265SDimitry Andric     if (!CI)
8281ad6265SDimitry Andric       continue;
8381ad6265SDimitry Andric 
8481ad6265SDimitry Andric     SmallVector<Value *> Args;
85*0fca6ea1SDimitry Andric     Value *DXILOpArg = B.getInt32(static_cast<unsigned>(DXILOp));
8681ad6265SDimitry Andric     Args.emplace_back(DXILOpArg);
8781ad6265SDimitry Andric     B.SetInsertPoint(CI);
88*0fca6ea1SDimitry Andric     if (isVectorArgExpansion(F)) {
89*0fca6ea1SDimitry Andric       SmallVector<Value *> NewArgs = argVectorFlatten(CI, B);
90*0fca6ea1SDimitry Andric       Args.append(NewArgs.begin(), NewArgs.end());
91*0fca6ea1SDimitry Andric     } else
92*0fca6ea1SDimitry Andric       Args.append(CI->arg_begin(), CI->arg_end());
93*0fca6ea1SDimitry Andric 
94*0fca6ea1SDimitry Andric     CallInst *DXILCI =
95*0fca6ea1SDimitry Andric         DXILB.createDXILOpCall(DXILOp, F.getReturnType(), OverloadTy, Args);
96972a253aSDimitry Andric 
9781ad6265SDimitry Andric     CI->replaceAllUsesWith(DXILCI);
9881ad6265SDimitry Andric     CI->eraseFromParent();
9981ad6265SDimitry Andric   }
10081ad6265SDimitry Andric   if (F.user_empty())
10181ad6265SDimitry Andric     F.eraseFromParent();
10281ad6265SDimitry Andric }
10381ad6265SDimitry Andric 
lowerIntrinsics(Module & M)10481ad6265SDimitry Andric static bool lowerIntrinsics(Module &M) {
10581ad6265SDimitry Andric   bool Updated = false;
10681ad6265SDimitry Andric 
10781ad6265SDimitry Andric #define DXIL_OP_INTRINSIC_MAP
10881ad6265SDimitry Andric #include "DXILOperation.inc"
10981ad6265SDimitry Andric #undef DXIL_OP_INTRINSIC_MAP
11081ad6265SDimitry Andric 
11181ad6265SDimitry Andric   for (Function &F : make_early_inc_range(M.functions())) {
11281ad6265SDimitry Andric     if (!F.isDeclaration())
11381ad6265SDimitry Andric       continue;
11481ad6265SDimitry Andric     Intrinsic::ID ID = F.getIntrinsicID();
11581ad6265SDimitry Andric     if (ID == Intrinsic::not_intrinsic)
11681ad6265SDimitry Andric       continue;
11781ad6265SDimitry Andric     auto LowerIt = LowerMap.find(ID);
11881ad6265SDimitry Andric     if (LowerIt == LowerMap.end())
11981ad6265SDimitry Andric       continue;
12081ad6265SDimitry Andric     lowerIntrinsic(LowerIt->second, F, M);
12181ad6265SDimitry Andric     Updated = true;
12281ad6265SDimitry Andric   }
12381ad6265SDimitry Andric   return Updated;
12481ad6265SDimitry Andric }
12581ad6265SDimitry Andric 
12681ad6265SDimitry Andric namespace {
12781ad6265SDimitry Andric /// A pass that transforms external global definitions into declarations.
12881ad6265SDimitry Andric class DXILOpLowering : public PassInfoMixin<DXILOpLowering> {
12981ad6265SDimitry Andric public:
run(Module & M,ModuleAnalysisManager &)13081ad6265SDimitry Andric   PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {
13181ad6265SDimitry Andric     if (lowerIntrinsics(M))
13281ad6265SDimitry Andric       return PreservedAnalyses::none();
13381ad6265SDimitry Andric     return PreservedAnalyses::all();
13481ad6265SDimitry Andric   }
13581ad6265SDimitry Andric };
13681ad6265SDimitry Andric } // namespace
13781ad6265SDimitry Andric 
13881ad6265SDimitry Andric namespace {
13981ad6265SDimitry Andric class DXILOpLoweringLegacy : public ModulePass {
14081ad6265SDimitry Andric public:
runOnModule(Module & M)14181ad6265SDimitry Andric   bool runOnModule(Module &M) override { return lowerIntrinsics(M); }
getPassName() const14281ad6265SDimitry Andric   StringRef getPassName() const override { return "DXIL Op Lowering"; }
DXILOpLoweringLegacy()14381ad6265SDimitry Andric   DXILOpLoweringLegacy() : ModulePass(ID) {}
14481ad6265SDimitry Andric 
14581ad6265SDimitry Andric   static char ID; // Pass identification.
getAnalysisUsage(llvm::AnalysisUsage & AU) const146*0fca6ea1SDimitry Andric   void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
147*0fca6ea1SDimitry Andric     // Specify the passes that your pass depends on
148*0fca6ea1SDimitry Andric     AU.addRequired<DXILIntrinsicExpansionLegacy>();
149*0fca6ea1SDimitry Andric   }
15081ad6265SDimitry Andric };
15181ad6265SDimitry Andric char DXILOpLoweringLegacy::ID = 0;
15281ad6265SDimitry Andric } // end anonymous namespace
15381ad6265SDimitry Andric 
15481ad6265SDimitry Andric INITIALIZE_PASS_BEGIN(DXILOpLoweringLegacy, DEBUG_TYPE, "DXIL Op Lowering",
15581ad6265SDimitry Andric                       false, false)
15681ad6265SDimitry Andric INITIALIZE_PASS_END(DXILOpLoweringLegacy, DEBUG_TYPE, "DXIL Op Lowering", false,
15781ad6265SDimitry Andric                     false)
15881ad6265SDimitry Andric 
createDXILOpLoweringLegacyPass()15981ad6265SDimitry Andric ModulePass *llvm::createDXILOpLoweringLegacyPass() {
16081ad6265SDimitry Andric   return new DXILOpLoweringLegacy();
16181ad6265SDimitry Andric }
162