LLVM  15.0.0git
DXILOpLowering.cpp
Go to the documentation of this file.
1 //===- DXILOpLower.cpp - Lowering LLVM intrinsic to DIXLOp function -------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file This file contains passes and utilities to lower llvm intrinsic call
10 /// to DXILOp function call.
11 //===----------------------------------------------------------------------===//
12 
13 #include "DXILConstants.h"
14 #include "DirectX.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/CodeGen/Passes.h"
17 #include "llvm/IR/IRBuilder.h"
18 #include "llvm/IR/Instruction.h"
19 #include "llvm/IR/Intrinsics.h"
20 #include "llvm/IR/IntrinsicsDirectX.h"
21 #include "llvm/IR/Module.h"
22 #include "llvm/IR/PassManager.h"
23 #include "llvm/Pass.h"
25 
26 #define DEBUG_TYPE "dxil-op-lower"
27 
28 using namespace llvm;
29 using namespace llvm::DXIL;
30 
31 constexpr StringLiteral DXILOpNamePrefix = "dx.op.";
32 
34  VOID = 1,
35  HALF = 1 << 1,
36  FLOAT = 1 << 2,
37  DOUBLE = 1 << 3,
38  I1 = 1 << 4,
39  I8 = 1 << 5,
40  I16 = 1 << 6,
41  I32 = 1 << 7,
42  I64 = 1 << 8,
43  UserDefineType = 1 << 9,
44  ObjectType = 1 << 10,
45 };
46 
47 static const char *getOverloadTypeName(OverloadKind Kind) {
48  switch (Kind) {
49  case OverloadKind::HALF:
50  return "f16";
52  return "f32";
54  return "f64";
55  case OverloadKind::I1:
56  return "i1";
57  case OverloadKind::I8:
58  return "i8";
59  case OverloadKind::I16:
60  return "i16";
61  case OverloadKind::I32:
62  return "i32";
63  case OverloadKind::I64:
64  return "i64";
65  case OverloadKind::VOID:
68  break;
69  }
70  llvm_unreachable("invalid overload type for name");
71  return "void";
72 }
73 
75  Type::TypeID T = Ty->getTypeID();
76  switch (T) {
77  case Type::VoidTyID:
78  return OverloadKind::VOID;
79  case Type::HalfTyID:
80  return OverloadKind::HALF;
81  case Type::FloatTyID:
82  return OverloadKind::FLOAT;
83  case Type::DoubleTyID:
84  return OverloadKind::DOUBLE;
85  case Type::IntegerTyID: {
86  IntegerType *ITy = cast<IntegerType>(Ty);
87  unsigned Bits = ITy->getBitWidth();
88  switch (Bits) {
89  case 1:
90  return OverloadKind::I1;
91  case 8:
92  return OverloadKind::I8;
93  case 16:
94  return OverloadKind::I16;
95  case 32:
96  return OverloadKind::I32;
97  case 64:
98  return OverloadKind::I64;
99  default:
100  llvm_unreachable("invalid overload type");
101  return OverloadKind::VOID;
102  }
103  }
104  case Type::PointerTyID:
106  case Type::StructTyID:
108  default:
109  llvm_unreachable("invalid overload type");
110  return OverloadKind::VOID;
111  }
112 }
113 
114 static std::string getTypeName(OverloadKind Kind, Type *Ty) {
116  return getOverloadTypeName(Kind);
117  } else if (Kind == OverloadKind::UserDefineType) {
118  StructType *ST = cast<StructType>(Ty);
119  return ST->getStructName().str();
120  } else if (Kind == OverloadKind::ObjectType) {
121  StructType *ST = cast<StructType>(Ty);
122  return ST->getStructName().str();
123  } else {
124  std::string Str;
125  raw_string_ostream OS(Str);
126  Ty->print(OS);
127  return OS.str();
128  }
129 }
130 
131 // Static properties.
133  DXIL::OpCode OpCode;
134  // Offset in DXILOpCodeNameTable.
136  DXIL::OpCodeClass OpCodeClass;
137  // Offset in DXILOpCodeClassNameTable.
141 };
142 
143 // Include getOpCodeClassName getOpCodeProperty and getOpCodeName which
144 // generated by tableGen.
145 #define DXIL_OP_OPERATION_TABLE
146 #include "DXILOperation.inc"
147 #undef DXIL_OP_OPERATION_TABLE
148 
149 static std::string constructOverloadName(OverloadKind Kind, Type *Ty,
150  const OpCodeProperty &Prop) {
151  if (Kind == OverloadKind::VOID) {
152  return (Twine(DXILOpNamePrefix) + getOpCodeClassName(Prop)).str();
153  }
154  return (Twine(DXILOpNamePrefix) + getOpCodeClassName(Prop) + "." +
155  getTypeName(Kind, Ty))
156  .str();
157 }
158 
159 static FunctionCallee createDXILOpFunction(DXIL::OpCode DXILOp, Function &F,
160  Module &M) {
161  const OpCodeProperty *Prop = getOpCodeProperty(DXILOp);
162 
163  // Get return type as overload type for DXILOp.
164  // Only simple mapping case here, so return type is good enough.
165  Type *OverloadTy = F.getReturnType();
166 
167  OverloadKind Kind = getOverloadKind(OverloadTy);
168  // FIXME: find the issue and report error in clang instead of check it in
169  // backend.
170  if ((Prop->OverloadTys & (uint16_t)Kind) == 0) {
171  llvm_unreachable("invalid overload");
172  }
173 
174  std::string FnName = constructOverloadName(Kind, OverloadTy, *Prop);
175  assert(!M.getFunction(FnName) && "Function already exists");
176 
177  auto &Ctx = M.getContext();
178  Type *OpCodeTy = Type::getInt32Ty(Ctx);
179 
180  SmallVector<Type *> ArgTypes;
181  // DXIL has i32 opcode as first arg.
182  ArgTypes.emplace_back(OpCodeTy);
183  FunctionType *FT = F.getFunctionType();
184  ArgTypes.append(FT->param_begin(), FT->param_end());
185  FunctionType *DXILOpFT = FunctionType::get(OverloadTy, ArgTypes, false);
186  return M.getOrInsertFunction(FnName, DXILOpFT);
187 }
188 
189 static void lowerIntrinsic(DXIL::OpCode DXILOp, Function &F, Module &M) {
190  auto DXILOpFn = createDXILOpFunction(DXILOp, F, M);
191  IRBuilder<> B(M.getContext());
192  Value *DXILOpArg = B.getInt32(static_cast<unsigned>(DXILOp));
193  for (User *U : make_early_inc_range(F.users())) {
194  CallInst *CI = dyn_cast<CallInst>(U);
195  if (!CI)
196  continue;
197 
199  Args.emplace_back(DXILOpArg);
200  Args.append(CI->arg_begin(), CI->arg_end());
201  B.SetInsertPoint(CI);
202  CallInst *DXILCI = B.CreateCall(DXILOpFn, Args);
203  LLVM_DEBUG(DXILCI->setName(getOpCodeName(DXILOp)));
204  CI->replaceAllUsesWith(DXILCI);
205  CI->eraseFromParent();
206  }
207  if (F.user_empty())
208  F.eraseFromParent();
209 }
210 
211 static bool lowerIntrinsics(Module &M) {
212  bool Updated = false;
213 
214 #define DXIL_OP_INTRINSIC_MAP
215 #include "DXILOperation.inc"
216 #undef DXIL_OP_INTRINSIC_MAP
217 
218  for (Function &F : make_early_inc_range(M.functions())) {
219  if (!F.isDeclaration())
220  continue;
221  Intrinsic::ID ID = F.getIntrinsicID();
223  continue;
224  auto LowerIt = LowerMap.find(ID);
225  if (LowerIt == LowerMap.end())
226  continue;
227  lowerIntrinsic(LowerIt->second, F, M);
228  Updated = true;
229  }
230  return Updated;
231 }
232 
233 namespace {
234 /// A pass that transforms external global definitions into declarations.
235 class DXILOpLowering : public PassInfoMixin<DXILOpLowering> {
236 public:
238  if (lowerIntrinsics(M))
239  return PreservedAnalyses::none();
240  return PreservedAnalyses::all();
241  }
242 };
243 } // namespace
244 
245 namespace {
246 class DXILOpLoweringLegacy : public ModulePass {
247 public:
248  bool runOnModule(Module &M) override { return lowerIntrinsics(M); }
249  StringRef getPassName() const override { return "DXIL Op Lowering"; }
250  DXILOpLoweringLegacy() : ModulePass(ID) {}
251 
252  static char ID; // Pass identification.
253 };
254 char DXILOpLoweringLegacy::ID = 0;
255 
256 } // end anonymous namespace
257 
258 INITIALIZE_PASS_BEGIN(DXILOpLoweringLegacy, DEBUG_TYPE, "DXIL Op Lowering",
259  false, false)
260 INITIALIZE_PASS_END(DXILOpLoweringLegacy, DEBUG_TYPE, "DXIL Op Lowering", false,
261  false)
262 
264  return new DXILOpLoweringLegacy();
265 }
getOverloadKind
static OverloadKind getOverloadKind(Type *Ty)
Definition: DXILOpLowering.cpp:74
llvm::PreservedAnalyses
A set of analyses that are preserved following a run of a transformation pass.
Definition: PassManager.h:152
llvm::Type::FloatTyID
@ FloatTyID
32-bit floating point type
Definition: Type.h:58
llvm::Type::DoubleTyID
@ DoubleTyID
64-bit floating point type
Definition: Type.h:59
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
M
We currently emits eax Perhaps this is what we really should generate is Is imull three or four cycles eax eax The current instruction priority is based on pattern complexity The former is more complex because it folds a load so the latter will not be emitted Perhaps we should use AddedComplexity to give LEA32r a higher priority We should always try to match LEA first since the LEA matching code does some estimate to determine whether the match is profitable if we care more about code then imull is better It s two bytes shorter than movl leal On a Pentium M
Definition: README.txt:252
llvm::ModulePass
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:248
llvm::PassInfoMixin
A CRTP mix-in to automatically provide informational APIs needed for passes.
Definition: PassManager.h:371
T
llvm::Function
Definition: Function.h:60
llvm::Type::VoidTyID
@ VoidTyID
type with no size
Definition: Type.h:63
Pass.h
llvm::raw_string_ostream
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:632
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1185
ErrorHandling.h
llvm::IRBuilder<>
llvm::FunctionType::get
static FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
Definition: Type.cpp:361
llvm::Type::getTypeID
TypeID getTypeID() const
Return the type id for the type.
Definition: Type.h:136
llvm::PreservedAnalyses::none
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition: PassManager.h:155
llvm::Type
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
Module.h
llvm::tgtok::Bits
@ Bits
Definition: TGLexer.h:50
UserDefineType
@ UserDefineType
Definition: DXILOpLowering.cpp:43
I64
@ I64
Definition: DXILOpLowering.cpp:42
llvm::Intrinsic::not_intrinsic
@ not_intrinsic
Definition: Intrinsics.h:45
llvm::CallBase::arg_begin
User::op_iterator arg_begin()
Return the iterator pointing to the beginning of the argument list.
Definition: InstrTypes.h:1316
llvm::Type::getInt32Ty
static IntegerType * getInt32Ty(LLVMContext &C)
Definition: Type.cpp:239
createDXILOpFunction
static FunctionCallee createDXILOpFunction(DXIL::OpCode DXILOp, Function &F, Module &M)
Definition: DXILOpLowering.cpp:159
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
I1
@ I1
Definition: DXILOpLowering.cpp:38
F
#define F(x, y, z)
Definition: MD5.cpp:55
Instruction.h
llvm::StringLiteral
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
Definition: StringRef.h:914
DirectX.h
OpCodeProperty::FuncAttr
llvm::Attribute::AttrKind FuncAttr
Definition: DXILOpLowering.cpp:140
llvm::SmallVectorImpl::append
void append(in_iter in_start, in_iter in_end)
Add the specified range to the end of the SmallVector.
Definition: SmallVector.h:667
llvm::User
Definition: User.h:44
Intrinsics.h
llvm::FunctionType::param_end
param_iterator param_end() const
Definition: DerivedTypes.h:129
llvm::Type::print
void print(raw_ostream &O, bool IsForDebug=false, bool NoDetails=false) const
Print the current type.
Definition: AsmWriter.cpp:4560
INITIALIZE_PASS_BEGIN
INITIALIZE_PASS_BEGIN(DXILOpLoweringLegacy, DEBUG_TYPE, "DXIL Op Lowering", false, false) INITIALIZE_PASS_END(DXILOpLoweringLegacy
llvm::createDXILOpLoweringLegacyPass
ModulePass * createDXILOpLoweringLegacyPass()
Pass to lowering LLVM intrinsic call to DXIL op function call.
Definition: DXILOpLowering.cpp:263
lowerIntrinsics
static bool lowerIntrinsics(Module &M)
Definition: DXILOpLowering.cpp:211
false
Definition: StackSlotColoring.cpp:141
B
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
llvm::IntegerType
Class to represent integer types.
Definition: DerivedTypes.h:40
llvm::FunctionType::param_begin
param_iterator param_begin() const
Definition: DerivedTypes.h:128
llvm::Value::setName
void setName(const Twine &Name)
Change the name of the value.
Definition: Value.cpp:372
llvm::Type::PointerTyID
@ PointerTyID
Pointers.
Definition: Type.h:73
OpCodeProperty::OpCodeNameOffset
unsigned OpCodeNameOffset
Definition: DXILOpLowering.cpp:135
llvm::lltok::Kind
Kind
Definition: LLToken.h:18
llvm::CallingConv::ID
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
INITIALIZE_PASS_END
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:58
llvm::dxil::PointerTypeAnalysis::run
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
Definition: PointerTypeAnalysis.cpp:101
VOID
@ VOID
Definition: DXILOpLowering.cpp:34
Passes.h
FLOAT
@ FLOAT
Definition: DXILOpLowering.cpp:36
OpCodeProperty
Definition: DXILOpLowering.cpp:132
OpCodeProperty::OpCodeClass
DXIL::OpCodeClass OpCodeClass
Definition: DXILOpLowering.cpp:136
llvm::Instruction::eraseFromParent
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Definition: Instruction.cpp:77
llvm::ARM_MB::ST
@ ST
Definition: ARMBaseInfo.h:73
llvm::DXIL
Definition: DXILConstants.h:16
Lowering
DXIL Op Lowering
Definition: DXILOpLowering.cpp:260
llvm::Attribute::AttrKind
AttrKind
This enumeration lists the attributes that can be associated with parameters, function results,...
Definition: Attributes.h:84
llvm::make_early_inc_range
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition: STLExtras.h:618
DXILConstants.h
DXILOpNamePrefix
constexpr StringLiteral DXILOpNamePrefix
Definition: DXILOpLowering.cpp:31
IRBuilder.h
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
I16
@ I16
Definition: DXILOpLowering.cpp:40
llvm::Module
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
llvm::CallBase::arg_end
User::op_iterator arg_end()
Return the iterator pointing to the end of the argument list.
Definition: InstrTypes.h:1322
llvm::StructType
Class to represent struct types.
Definition: DerivedTypes.h:213
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
llvm::getTypeName
StringRef getTypeName()
We provide a function which tries to compute the (demangled) name of a type statically.
Definition: TypeName.h:27
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:143
ObjectType
@ ObjectType
Definition: DXILOpLowering.cpp:44
getOverloadTypeName
static const char * getOverloadTypeName(OverloadKind Kind)
Definition: DXILOpLowering.cpp:47
llvm::Value::replaceAllUsesWith
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:529
HALF
@ HALF
Definition: DXILOpLowering.cpp:35
OpCodeProperty::OverloadTys
uint16_t OverloadTys
Definition: DXILOpLowering.cpp:139
I32
@ I32
Definition: DXILOpLowering.cpp:41
OverloadKind
OverloadKind
Definition: DXILOpLowering.cpp:33
llvm::Type::IntegerTyID
@ IntegerTyID
Arbitrary bit width integers.
Definition: Type.h:71
llvm::Twine
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:83
constructOverloadName
static std::string constructOverloadName(OverloadKind Kind, Type *Ty, const OpCodeProperty &Prop)
Definition: DXILOpLowering.cpp:149
uint16_t
llvm::AMDGPU::SendMsg::Op
Op
Definition: SIDefines.h:348
llvm::PreservedAnalyses::all
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: PassManager.h:158
OpCodeProperty::OpCode
DXIL::OpCode OpCode
Definition: DXILOpLowering.cpp:133
PassManager.h
I8
@ I8
Definition: DXILOpLowering.cpp:39
DEBUG_TYPE
#define DEBUG_TYPE
Definition: DXILOpLowering.cpp:26
llvm::Type::StructTyID
@ StructTyID
Structures.
Definition: Type.h:74
SmallVector.h
llvm::IntegerType::getBitWidth
unsigned getBitWidth() const
Get the number of bits in this IntegerType.
Definition: DerivedTypes.h:72
llvm::FunctionCallee
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
Definition: DerivedTypes.h:165
llvm::AnalysisManager
A container for analyses that lazily runs them and caches their results.
Definition: InstructionSimplify.h:42
llvm::CallInst
This class represents a function call, abstracting a target machine's calling convention.
Definition: Instructions.h:1461
OpCodeProperty::OpCodeClassNameOffset
unsigned OpCodeClassNameOffset
Definition: DXILOpLowering.cpp:138
llvm::AMDGPU::HSAMD::Kernel::Key::Args
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
Definition: AMDGPUMetadata.h:394
llvm::Type::TypeID
TypeID
Definitions of all of the base types for the Type system.
Definition: Type.h:54
llvm::raw_string_ostream::str
std::string & str()
Returns the string's reference.
Definition: raw_ostream.h:650
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
lowerIntrinsic
static void lowerIntrinsic(DXIL::OpCode DXILOp, Function &F, Module &M)
Definition: DXILOpLowering.cpp:189
llvm::Type::HalfTyID
@ HalfTyID
16-bit floating point type
Definition: Type.h:56
llvm::FunctionType
Class to represent function types.
Definition: DerivedTypes.h:103
llvm::SmallVectorImpl::emplace_back
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:927
DOUBLE
@ DOUBLE
Definition: DXILOpLowering.cpp:37
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:38