LLVM  16.0.0git
DXILOpBuilder.cpp
Go to the documentation of this file.
1 //===- DXILOpBuilder.cpp - Helper class for build DIXLOp functions --------===//
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 class to help build DXIL op functions.
10 //===----------------------------------------------------------------------===//
11 
12 #include "DXILOpBuilder.h"
13 #include "DXILConstants.h"
14 #include "llvm/IR/IRBuilder.h"
15 #include "llvm/IR/Module.h"
18 
19 using namespace llvm;
20 using namespace llvm::dxil;
21 
22 constexpr StringLiteral DXILOpNamePrefix = "dx.op.";
23 
24 namespace {
25 
26 enum OverloadKind : uint16_t {
27  VOID = 1,
28  HALF = 1 << 1,
29  FLOAT = 1 << 2,
30  DOUBLE = 1 << 3,
31  I1 = 1 << 4,
32  I8 = 1 << 5,
33  I16 = 1 << 6,
34  I32 = 1 << 7,
35  I64 = 1 << 8,
36  UserDefineType = 1 << 9,
37  ObjectType = 1 << 10,
38 };
39 
40 } // namespace
41 
42 static const char *getOverloadTypeName(OverloadKind Kind) {
43  switch (Kind) {
44  case OverloadKind::HALF:
45  return "f16";
46  case OverloadKind::FLOAT:
47  return "f32";
48  case OverloadKind::DOUBLE:
49  return "f64";
50  case OverloadKind::I1:
51  return "i1";
52  case OverloadKind::I8:
53  return "i8";
54  case OverloadKind::I16:
55  return "i16";
56  case OverloadKind::I32:
57  return "i32";
58  case OverloadKind::I64:
59  return "i64";
60  case OverloadKind::VOID:
61  case OverloadKind::ObjectType:
62  case OverloadKind::UserDefineType:
63  break;
64  }
65  llvm_unreachable("invalid overload type for name");
66  return "void";
67 }
68 
69 static OverloadKind getOverloadKind(Type *Ty) {
70  Type::TypeID T = Ty->getTypeID();
71  switch (T) {
72  case Type::VoidTyID:
73  return OverloadKind::VOID;
74  case Type::HalfTyID:
75  return OverloadKind::HALF;
76  case Type::FloatTyID:
77  return OverloadKind::FLOAT;
78  case Type::DoubleTyID:
79  return OverloadKind::DOUBLE;
80  case Type::IntegerTyID: {
81  IntegerType *ITy = cast<IntegerType>(Ty);
82  unsigned Bits = ITy->getBitWidth();
83  switch (Bits) {
84  case 1:
85  return OverloadKind::I1;
86  case 8:
87  return OverloadKind::I8;
88  case 16:
89  return OverloadKind::I16;
90  case 32:
91  return OverloadKind::I32;
92  case 64:
93  return OverloadKind::I64;
94  default:
95  llvm_unreachable("invalid overload type");
96  return OverloadKind::VOID;
97  }
98  }
99  case Type::PointerTyID:
100  return OverloadKind::UserDefineType;
101  case Type::StructTyID:
102  return OverloadKind::ObjectType;
103  default:
104  llvm_unreachable("invalid overload type");
105  return OverloadKind::VOID;
106  }
107 }
108 
109 static std::string getTypeName(OverloadKind Kind, Type *Ty) {
110  if (Kind < OverloadKind::UserDefineType) {
111  return getOverloadTypeName(Kind);
112  } else if (Kind == OverloadKind::UserDefineType) {
113  StructType *ST = cast<StructType>(Ty);
114  return ST->getStructName().str();
115  } else if (Kind == OverloadKind::ObjectType) {
116  StructType *ST = cast<StructType>(Ty);
117  return ST->getStructName().str();
118  } else {
119  std::string Str;
120  raw_string_ostream OS(Str);
121  Ty->print(OS);
122  return OS.str();
123  }
124 }
125 
126 // Static properties.
128  dxil::OpCode OpCode;
129  // Offset in DXILOpCodeNameTable.
131  dxil::OpCodeClass OpCodeClass;
132  // Offset in DXILOpCodeClassNameTable.
136  int OverloadParamIndex; // parameter index which control the overload.
137  // When < 0, should be only 1 overload type.
138  unsigned NumOfParameters; // Number of parameters include return value.
139  unsigned ParameterTableOffset; // Offset in ParameterTable.
140 };
141 
142 // Include getOpCodeClassName getOpCodeProperty, getOpCodeName and
143 // getOpCodeParameterKind which generated by tableGen.
144 #define DXIL_OP_OPERATION_TABLE
145 #include "DXILOperation.inc"
146 #undef DXIL_OP_OPERATION_TABLE
147 
148 static std::string constructOverloadName(OverloadKind Kind, Type *Ty,
149  const OpCodeProperty &Prop) {
150  if (Kind == OverloadKind::VOID) {
151  return (Twine(DXILOpNamePrefix) + getOpCodeClassName(Prop)).str();
152  }
153  return (Twine(DXILOpNamePrefix) + getOpCodeClassName(Prop) + "." +
154  getTypeName(Kind, Ty))
155  .str();
156 }
157 
158 static std::string constructOverloadTypeName(OverloadKind Kind,
160  if (Kind == OverloadKind::VOID)
161  return TypeName.str();
162 
163  assert(Kind < OverloadKind::UserDefineType && "invalid overload kind");
164  return (Twine(TypeName) + getOverloadTypeName(Kind)).str();
165 }
166 
168  ArrayRef<Type *> EltTys,
169  LLVMContext &Ctx) {
171  if (ST)
172  return ST;
173 
174  return StructType::create(Ctx, EltTys, Name);
175 }
176 
177 static StructType *getResRetType(Type *OverloadTy, LLVMContext &Ctx) {
178  OverloadKind Kind = getOverloadKind(OverloadTy);
179  std::string TypeName = constructOverloadTypeName(Kind, "dx.types.ResRet.");
180  Type *FieldTypes[5] = {OverloadTy, OverloadTy, OverloadTy, OverloadTy,
181  Type::getInt32Ty(Ctx)};
182  return getOrCreateStructType(TypeName, FieldTypes, Ctx);
183 }
184 
186  return getOrCreateStructType("dx.types.Handle", Type::getInt8PtrTy(Ctx), Ctx);
187 }
188 
189 static Type *getTypeFromParameterKind(ParameterKind Kind, Type *OverloadTy) {
190  auto &Ctx = OverloadTy->getContext();
191  switch (Kind) {
192  case ParameterKind::VOID:
193  return Type::getVoidTy(Ctx);
194  case ParameterKind::HALF:
195  return Type::getHalfTy(Ctx);
197  return Type::getFloatTy(Ctx);
199  return Type::getDoubleTy(Ctx);
200  case ParameterKind::I1:
201  return Type::getInt1Ty(Ctx);
202  case ParameterKind::I8:
203  return Type::getInt8Ty(Ctx);
204  case ParameterKind::I16:
205  return Type::getInt16Ty(Ctx);
206  case ParameterKind::I32:
207  return Type::getInt32Ty(Ctx);
208  case ParameterKind::I64:
209  return Type::getInt64Ty(Ctx);
211  return OverloadTy;
213  return getResRetType(OverloadTy, Ctx);
215  return getHandleType(Ctx);
216  default:
217  break;
218  }
219  llvm_unreachable("Invalid parameter kind");
220  return nullptr;
221 }
222 
224  Type *OverloadTy) {
225  SmallVector<Type *> ArgTys;
226 
227  auto ParamKinds = getOpCodeParameterKind(*Prop);
228 
229  for (unsigned I = 0; I < Prop->NumOfParameters; ++I) {
230  ParameterKind Kind = ParamKinds[I];
231  ArgTys.emplace_back(getTypeFromParameterKind(Kind, OverloadTy));
232  }
233  return FunctionType::get(
234  ArgTys[0], ArrayRef<Type *>(&ArgTys[1], ArgTys.size() - 1), false);
235 }
236 
237 static FunctionCallee getOrCreateDXILOpFunction(dxil::OpCode DXILOp,
238  Type *OverloadTy, Module &M) {
239  const OpCodeProperty *Prop = getOpCodeProperty(DXILOp);
240 
241  OverloadKind Kind = getOverloadKind(OverloadTy);
242  // FIXME: find the issue and report error in clang instead of check it in
243  // backend.
244  if ((Prop->OverloadTys & (uint16_t)Kind) == 0) {
245  llvm_unreachable("invalid overload");
246  }
247 
248  std::string FnName = constructOverloadName(Kind, OverloadTy, *Prop);
249  // Dependent on name to dedup.
250  if (auto *Fn = M.getFunction(FnName))
251  return FunctionCallee(Fn);
252 
253  FunctionType *DXILOpFT = getDXILOpFunctionType(Prop, OverloadTy);
254  return M.getOrInsertFunction(FnName, DXILOpFT);
255 }
256 
257 namespace llvm {
258 namespace dxil {
259 
260 CallInst *DXILOpBuilder::createDXILOpCall(dxil::OpCode OpCode, Type *OverloadTy,
262  auto Fn = getOrCreateDXILOpFunction(OpCode, OverloadTy, M);
263  SmallVector<Value *> FullArgs;
264  FullArgs.emplace_back(B.getInt32((int32_t)OpCode));
265  FullArgs.append(Args.begin(), Args.end());
266  return B.CreateCall(Fn, FullArgs);
267 }
268 
270  bool NoOpCodeParam) {
271 
272  const OpCodeProperty *Prop = getOpCodeProperty(OpCode);
273  if (Prop->OverloadParamIndex < 0) {
274  auto &Ctx = FT->getContext();
275  // When only has 1 overload type, just return it.
276  switch (Prop->OverloadTys) {
277  case OverloadKind::VOID:
278  return Type::getVoidTy(Ctx);
279  case OverloadKind::HALF:
280  return Type::getHalfTy(Ctx);
281  case OverloadKind::FLOAT:
282  return Type::getFloatTy(Ctx);
283  case OverloadKind::DOUBLE:
284  return Type::getDoubleTy(Ctx);
285  case OverloadKind::I1:
286  return Type::getInt1Ty(Ctx);
287  case OverloadKind::I8:
288  return Type::getInt8Ty(Ctx);
289  case OverloadKind::I16:
290  return Type::getInt16Ty(Ctx);
291  case OverloadKind::I32:
292  return Type::getInt32Ty(Ctx);
293  case OverloadKind::I64:
294  return Type::getInt64Ty(Ctx);
295  default:
296  llvm_unreachable("invalid overload type");
297  return nullptr;
298  }
299  }
300 
301  // Prop->OverloadParamIndex is 0, overload type is FT->getReturnType().
302  Type *OverloadType = FT->getReturnType();
303  if (Prop->OverloadParamIndex != 0) {
304  // Skip Return Type and Type for DXIL opcode.
305  const unsigned SkipedParam = NoOpCodeParam ? 2 : 1;
306  OverloadType = FT->getParamType(Prop->OverloadParamIndex - SkipedParam);
307  }
308 
309  auto ParamKinds = getOpCodeParameterKind(*Prop);
310  auto Kind = ParamKinds[Prop->OverloadParamIndex];
311  // For ResRet and CBufferRet, OverloadTy is in field of StructType.
312  if (Kind == ParameterKind::CBUFFER_RET ||
313  Kind == ParameterKind::RESOURCE_RET) {
314  auto *ST = cast<StructType>(OverloadType);
315  OverloadType = ST->getElementType(0);
316  }
317  return OverloadType;
318 }
319 
320 const char *DXILOpBuilder::getOpCodeName(dxil::OpCode DXILOp) {
321  return ::getOpCodeName(DXILOp);
322 }
323 } // namespace dxil
324 } // namespace llvm
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:18
llvm::Type::getInt1Ty
static IntegerType * getInt1Ty(LLVMContext &C)
Definition: Type.cpp:236
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::dxil::ParameterKind::I1
@ I1
llvm::Type::getInt8PtrTy
static PointerType * getInt8PtrTy(LLVMContext &C, unsigned AS=0)
Definition: Type.cpp:291
llvm::dxil::ParameterKind::I16
@ I16
constructOverloadName
static std::string constructOverloadName(OverloadKind Kind, Type *Ty, const OpCodeProperty &Prop)
Definition: DXILOpBuilder.cpp:148
llvm::Type::VoidTyID
@ VoidTyID
type with no size
Definition: Type.h:63
llvm::raw_string_ostream
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:629
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1199
ErrorHandling.h
getDXILOpFunctionType
static FunctionType * getDXILOpFunctionType(const OpCodeProperty *Prop, Type *OverloadTy)
Definition: DXILOpBuilder.cpp:223
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::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
OpCodeProperty::OpCodeClass
dxil::OpCodeClass OpCodeClass
Definition: DXILOpBuilder.cpp:131
llvm::StructType::getTypeByName
static StructType * getTypeByName(LLVMContext &C, StringRef Name)
Return the type with the specified name, or null if there is none by that name.
Definition: Type.cpp:623
T
#define T
Definition: Mips16ISelLowering.cpp:341
llvm::StructType::create
static StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
Definition: Type.cpp:513
DXILOpNamePrefix
constexpr StringLiteral DXILOpNamePrefix
Definition: DXILOpBuilder.cpp:22
llvm::Type::getInt8Ty
static IntegerType * getInt8Ty(LLVMContext &C)
Definition: Type.cpp:237
llvm::Type::getInt32Ty
static IntegerType * getInt32Ty(LLVMContext &C)
Definition: Type.cpp:239
llvm::dxil::ParameterKind::I8
@ I8
getHandleType
static StructType * getHandleType(LLVMContext &Ctx)
Definition: DXILOpBuilder.cpp:185
OpCodeProperty::OpCode
dxil::OpCode OpCode
Definition: DXILOpBuilder.cpp:128
llvm::dxil::DXILOpBuilder::createDXILOpCall
CallInst * createDXILOpCall(dxil::OpCode OpCode, Type *OverloadTy, llvm::iterator_range< Use * > Args)
Definition: DXILOpBuilder.cpp:260
llvm::StringLiteral
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
Definition: StringRef.h:845
constructOverloadTypeName
static std::string constructOverloadTypeName(OverloadKind Kind, StringRef TypeName)
Definition: DXILOpBuilder.cpp:158
OpCodeProperty::ParameterTableOffset
unsigned ParameterTableOffset
Definition: DXILOpBuilder.cpp:139
OpCodeProperty::FuncAttr
llvm::Attribute::AttrKind FuncAttr
Definition: DXILOpBuilder.cpp:135
getOverloadTypeName
static const char * getOverloadTypeName(OverloadKind Kind)
Definition: DXILOpBuilder.cpp:42
llvm::Type::getDoubleTy
static Type * getDoubleTy(LLVMContext &C)
Definition: Type.cpp:227
llvm::dxil::ParameterKind::I32
@ I32
llvm::Type::print
void print(raw_ostream &O, bool IsForDebug=false, bool NoDetails=false) const
Print the current type.
Definition: AsmWriter.cpp:4650
OpCodeProperty::OverloadParamIndex
int OverloadParamIndex
Definition: DXILOpBuilder.cpp:136
B
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
llvm::IntegerType
Class to represent integer types.
Definition: DerivedTypes.h:40
llvm::SmallVectorImpl::append
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
Definition: SmallVector.h:687
llvm::Type::PointerTyID
@ PointerTyID
Pointers.
Definition: Type.h:73
OpCodeProperty::OpCodeNameOffset
unsigned OpCodeNameOffset
Definition: DXILOpBuilder.cpp:130
llvm::dxil::ParameterKind::VOID
@ VOID
llvm::dxil::DXILOpBuilder::getOverloadTy
Type * getOverloadTy(dxil::OpCode OpCode, FunctionType *FT, bool NoOpCodeParam)
Definition: DXILOpBuilder.cpp:269
OpCodeProperty
Definition: DXILOpBuilder.cpp:127
DXILOpBuilder.h
llvm::dxil::ParameterKind::I64
@ I64
llvm::dxil::ParameterKind::FLOAT
@ FLOAT
llvm::dxil
Definition: DXILOperationCommon.h:23
OpCodeProperty::NumOfParameters
unsigned NumOfParameters
Definition: DXILOpBuilder.cpp:138
llvm::ARM_MB::ST
@ ST
Definition: ARMBaseInfo.h:73
llvm::dxil::ParameterKind
ParameterKind
Definition: DXILOperationCommon.h:25
llvm::LLVMContext
This is an important class for using LLVM in a threaded context.
Definition: LLVMContext.h:67
llvm::dxil::ParameterKind::CBUFFER_RET
@ CBUFFER_RET
I
#define I(x, y, z)
Definition: MD5.cpp:58
llvm::FunctionType::getParamType
Type * getParamType(unsigned i) const
Parameter type accessors.
Definition: DerivedTypes.h:135
llvm::Attribute::AttrKind
AttrKind
This enumeration lists the attributes that can be associated with parameters, function results,...
Definition: Attributes.h:85
getOverloadKind
static OverloadKind getOverloadKind(Type *Ty)
Definition: DXILOpBuilder.cpp:69
DXILConstants.h
IRBuilder.h
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::Module
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
llvm::ArrayRef
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: APInt.h:32
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:50
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
llvm::dxil::ParameterKind::HALF
@ HALF
getResRetType
static StructType * getResRetType(Type *OverloadTy, LLVMContext &Ctx)
Definition: DXILOpBuilder.cpp:177
OpCodeProperty::OverloadTys
uint16_t OverloadTys
Definition: DXILOpBuilder.cpp:134
llvm::Type::getContext
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
Definition: Type.h:128
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:81
llvm::Type::getInt64Ty
static IntegerType * getInt64Ty(LLVMContext &C)
Definition: Type.cpp:240
llvm::dxil::ParameterKind::DXIL_HANDLE
@ DXIL_HANDLE
uint16_t
llvm::Type::getHalfTy
static Type * getHalfTy(LLVMContext &C)
Definition: Type.cpp:224
getTypeFromParameterKind
static Type * getTypeFromParameterKind(ParameterKind Kind, Type *OverloadTy)
Definition: DXILOpBuilder.cpp:189
llvm::dxil::ParameterKind::OVERLOAD
@ OVERLOAD
llvm::AMDGPU::HSAMD::Kernel::Arg::Key::TypeName
constexpr char TypeName[]
Key for Kernel::Arg::Metadata::mTypeName.
Definition: AMDGPUMetadata.h:175
llvm::Type::getVoidTy
static Type * getVoidTy(LLVMContext &C)
Definition: Type.cpp:222
llvm::Type::StructTyID
@ StructTyID
Structures.
Definition: Type.h:74
llvm::IntegerType::getBitWidth
unsigned getBitWidth() const
Get the number of bits in this IntegerType.
Definition: DerivedTypes.h:72
llvm::iterator_range
A range adaptor for a pair of iterators.
Definition: iterator_range.h:30
llvm::dxil::DXILOpBuilder::getOpCodeName
static const char * getOpCodeName(dxil::OpCode DXILOp)
Definition: DXILOpBuilder.cpp:320
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::dxil::ParameterKind::RESOURCE_RET
@ RESOURCE_RET
llvm::Type::getInt16Ty
static IntegerType * getInt16Ty(LLVMContext &C)
Definition: Type.cpp:238
DXILOperationCommon.h
llvm::CallInst
This class represents a function call, abstracting a target machine's calling convention.
Definition: Instructions.h:1474
OpCodeProperty::OpCodeClassNameOffset
unsigned OpCodeClassNameOffset
Definition: DXILOpBuilder.cpp:133
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
getOrCreateDXILOpFunction
static FunctionCallee getOrCreateDXILOpFunction(dxil::OpCode DXILOp, Type *OverloadTy, Module &M)
Definition: DXILOpBuilder.cpp:237
getOrCreateStructType
static StructType * getOrCreateStructType(StringRef Name, ArrayRef< Type * > EltTys, LLVMContext &Ctx)
Definition: DXILOpBuilder.cpp:167
llvm::raw_string_ostream::str
std::string & str()
Returns the string's reference.
Definition: raw_ostream.h:647
llvm::FunctionType::getReturnType
Type * getReturnType() const
Definition: DerivedTypes.h:124
llvm::dxil::ParameterKind::DOUBLE
@ DOUBLE
llvm::Type::HalfTyID
@ HalfTyID
16-bit floating point type
Definition: Type.h:56
llvm::Type::getFloatTy
static Type * getFloatTy(LLVMContext &C)
Definition: Type.cpp:226
llvm::FunctionType
Class to represent function types.
Definition: DerivedTypes.h:103
llvm::SmallVectorImpl::emplace_back
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:941