Path: blob/main/contrib/llvm-project/llvm/lib/Target/DirectX/DXILOpLowering.cpp
35266 views
//===- DXILOpLower.cpp - Lowering LLVM intrinsic to DIXLOp function -------===//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//===----------------------------------------------------------------------===//7///8/// \file This file contains passes and utilities to lower llvm intrinsic call9/// to DXILOp function call.10//===----------------------------------------------------------------------===//1112#include "DXILConstants.h"13#include "DXILIntrinsicExpansion.h"14#include "DXILOpBuilder.h"15#include "DirectX.h"16#include "llvm/ADT/SmallVector.h"17#include "llvm/CodeGen/Passes.h"18#include "llvm/IR/IRBuilder.h"19#include "llvm/IR/Instruction.h"20#include "llvm/IR/Intrinsics.h"21#include "llvm/IR/IntrinsicsDirectX.h"22#include "llvm/IR/Module.h"23#include "llvm/IR/PassManager.h"24#include "llvm/Pass.h"25#include "llvm/Support/ErrorHandling.h"2627#define DEBUG_TYPE "dxil-op-lower"2829using namespace llvm;30using namespace llvm::dxil;3132static bool isVectorArgExpansion(Function &F) {33switch (F.getIntrinsicID()) {34case Intrinsic::dx_dot2:35case Intrinsic::dx_dot3:36case Intrinsic::dx_dot4:37return true;38}39return false;40}4142static SmallVector<Value *> populateOperands(Value *Arg, IRBuilder<> &Builder) {43SmallVector<Value *> ExtractedElements;44auto *VecArg = dyn_cast<FixedVectorType>(Arg->getType());45for (unsigned I = 0; I < VecArg->getNumElements(); ++I) {46Value *Index = ConstantInt::get(Type::getInt32Ty(Arg->getContext()), I);47Value *ExtractedElement = Builder.CreateExtractElement(Arg, Index);48ExtractedElements.push_back(ExtractedElement);49}50return ExtractedElements;51}5253static SmallVector<Value *> argVectorFlatten(CallInst *Orig,54IRBuilder<> &Builder) {55// Note: arg[NumOperands-1] is a pointer and is not needed by our flattening.56unsigned NumOperands = Orig->getNumOperands() - 1;57assert(NumOperands > 0);58Value *Arg0 = Orig->getOperand(0);59[[maybe_unused]] auto *VecArg0 = dyn_cast<FixedVectorType>(Arg0->getType());60assert(VecArg0);61SmallVector<Value *> NewOperands = populateOperands(Arg0, Builder);62for (unsigned I = 1; I < NumOperands; ++I) {63Value *Arg = Orig->getOperand(I);64[[maybe_unused]] auto *VecArg = dyn_cast<FixedVectorType>(Arg->getType());65assert(VecArg);66assert(VecArg0->getElementType() == VecArg->getElementType());67assert(VecArg0->getNumElements() == VecArg->getNumElements());68auto NextOperandList = populateOperands(Arg, Builder);69NewOperands.append(NextOperandList.begin(), NextOperandList.end());70}71return NewOperands;72}7374static void lowerIntrinsic(dxil::OpCode DXILOp, Function &F, Module &M) {75IRBuilder<> B(M.getContext());76DXILOpBuilder DXILB(M, B);77Type *OverloadTy = DXILB.getOverloadTy(DXILOp, F.getFunctionType());78for (User *U : make_early_inc_range(F.users())) {79CallInst *CI = dyn_cast<CallInst>(U);80if (!CI)81continue;8283SmallVector<Value *> Args;84Value *DXILOpArg = B.getInt32(static_cast<unsigned>(DXILOp));85Args.emplace_back(DXILOpArg);86B.SetInsertPoint(CI);87if (isVectorArgExpansion(F)) {88SmallVector<Value *> NewArgs = argVectorFlatten(CI, B);89Args.append(NewArgs.begin(), NewArgs.end());90} else91Args.append(CI->arg_begin(), CI->arg_end());9293CallInst *DXILCI =94DXILB.createDXILOpCall(DXILOp, F.getReturnType(), OverloadTy, Args);9596CI->replaceAllUsesWith(DXILCI);97CI->eraseFromParent();98}99if (F.user_empty())100F.eraseFromParent();101}102103static bool lowerIntrinsics(Module &M) {104bool Updated = false;105106#define DXIL_OP_INTRINSIC_MAP107#include "DXILOperation.inc"108#undef DXIL_OP_INTRINSIC_MAP109110for (Function &F : make_early_inc_range(M.functions())) {111if (!F.isDeclaration())112continue;113Intrinsic::ID ID = F.getIntrinsicID();114if (ID == Intrinsic::not_intrinsic)115continue;116auto LowerIt = LowerMap.find(ID);117if (LowerIt == LowerMap.end())118continue;119lowerIntrinsic(LowerIt->second, F, M);120Updated = true;121}122return Updated;123}124125namespace {126/// A pass that transforms external global definitions into declarations.127class DXILOpLowering : public PassInfoMixin<DXILOpLowering> {128public:129PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {130if (lowerIntrinsics(M))131return PreservedAnalyses::none();132return PreservedAnalyses::all();133}134};135} // namespace136137namespace {138class DXILOpLoweringLegacy : public ModulePass {139public:140bool runOnModule(Module &M) override { return lowerIntrinsics(M); }141StringRef getPassName() const override { return "DXIL Op Lowering"; }142DXILOpLoweringLegacy() : ModulePass(ID) {}143144static char ID; // Pass identification.145void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {146// Specify the passes that your pass depends on147AU.addRequired<DXILIntrinsicExpansionLegacy>();148}149};150char DXILOpLoweringLegacy::ID = 0;151} // end anonymous namespace152153INITIALIZE_PASS_BEGIN(DXILOpLoweringLegacy, DEBUG_TYPE, "DXIL Op Lowering",154false, false)155INITIALIZE_PASS_END(DXILOpLoweringLegacy, DEBUG_TYPE, "DXIL Op Lowering", false,156false)157158ModulePass *llvm::createDXILOpLoweringLegacyPass() {159return new DXILOpLoweringLegacy();160}161162163