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/Module.h"
21 #include "llvm/IR/PassManager.h"
22 #include "llvm/Pass.h"
24 
25 #define DEBUG_TYPE "dxil-op-lower"
26 
27 using namespace llvm;
28 using namespace llvm::DXIL;
29 
30 constexpr StringLiteral DXILOpNamePrefix = "dx.op.";
31 
33  VOID = 1,
34  HALF = 1 << 1,
35  FLOAT = 1 << 2,
36  DOUBLE = 1 << 3,
37  I1 = 1 << 4,
38  I8 = 1 << 5,
39  I16 = 1 << 6,
40  I32 = 1 << 7,
41  I64 = 1 << 8,
42  UserDefineType = 1 << 9,
43  ObjectType = 1 << 10,
44 };
45 
46 static const char *getOverloadTypeName(OverloadKind Kind) {
47  switch (Kind) {
48  case OverloadKind::HALF:
49  return "f16";
51  return "f32";
53  return "f64";
54  case OverloadKind::I1:
55  return "i1";
56  case OverloadKind::I8:
57  return "i8";
58  case OverloadKind::I16:
59  return "i16";
60  case OverloadKind::I32:
61  return "i32";
62  case OverloadKind::I64:
63  return "i64";
64  case OverloadKind::VOID:
67  break;
68  }
69  llvm_unreachable("invalid overload type for name");
70  return "void";
71 }
72 
74  Type::TypeID T = Ty->getTypeID();
75  switch (T) {
76  case Type::VoidTyID:
77  return OverloadKind::VOID;
78  case Type::HalfTyID:
79  return OverloadKind::HALF;
80  case Type::FloatTyID:
81  return OverloadKind::FLOAT;
82  case Type::DoubleTyID:
83  return OverloadKind::DOUBLE;
84  case Type::IntegerTyID: {
85  IntegerType *ITy = cast<IntegerType>(Ty);
86  unsigned Bits = ITy->getBitWidth();
87  switch (Bits) {
88  case 1:
89  return OverloadKind::I1;
90  case 8:
91  return OverloadKind::I8;
92  case 16:
93  return OverloadKind::I16;
94  case 32:
95  return OverloadKind::I32;
96  case 64:
97  return OverloadKind::I64;
98  default:
99  llvm_unreachable("invalid overload type");
100  return OverloadKind::VOID;
101  }
102  }
103  case Type::PointerTyID:
105  case Type::StructTyID:
107  default:
108  llvm_unreachable("invalid overload type");
109  return OverloadKind::VOID;
110  }
111 }
112 
113 static std::string getTypeName(OverloadKind Kind, Type *Ty) {
115  return getOverloadTypeName(Kind);
116  } else if (Kind == OverloadKind::UserDefineType) {
117  StructType *ST = cast<StructType>(Ty);
118  return ST->getStructName().str();
119  } else if (Kind == OverloadKind::ObjectType) {
120  StructType *ST = cast<StructType>(Ty);
121  return ST->getStructName().str();
122  } else {
123  std::string Str;
124  raw_string_ostream OS(Str);
125  Ty->print(OS);
126  return OS.str();
127  }
128 }
129 
130 // Static properties.
132  DXIL::OpCode OpCode;
133  // Offset in DXILOpCodeNameTable.
135  DXIL::OpCodeClass OpCodeClass;
136  // Offset in DXILOpCodeClassNameTable.
140 };
141 
142 // Include getOpCodeClassName getOpCodeProperty and getOpCodeName which
143 // 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 FunctionCallee createDXILOpFunction(DXIL::OpCode DXILOp, Function &F,
159  Module &M) {
160  const OpCodeProperty *Prop = getOpCodeProperty(DXILOp);
161 
162  // Get return type as overload type for DXILOp.
163  // Only simple mapping case here, so return type is good enough.
164  Type *OverloadTy = F.getReturnType();
165 
166  OverloadKind Kind = getOverloadKind(OverloadTy);
167  // FIXME: find the issue and report error in clang instead of check it in
168  // backend.
169  if ((Prop->OverloadTys & (uint16_t)Kind) == 0) {
170  llvm_unreachable("invalid overload");
171  }
172 
173  std::string FnName = constructOverloadName(Kind, OverloadTy, *Prop);
174  assert(!M.getFunction(FnName) && "Function already exists");
175 
176  auto &Ctx = M.getContext();
177  Type *OpCodeTy = Type::getInt32Ty(Ctx);
178 
179  SmallVector<Type *> ArgTypes;
180  // DXIL has i32 opcode as first arg.
181  ArgTypes.emplace_back(OpCodeTy);
182  FunctionType *FT = F.getFunctionType();
183  ArgTypes.append(FT->param_begin(), FT->param_end());
184  FunctionType *DXILOpFT = FunctionType::get(OverloadTy, ArgTypes, false);
185  return M.getOrInsertFunction(FnName, DXILOpFT);
186 }
187 
188 static void lowerIntrinsic(DXIL::OpCode DXILOp, Function &F, Module &M) {
189  auto DXILOpFn = createDXILOpFunction(DXILOp, F, M);
190  IRBuilder<> B(M.getContext());
191  Value *DXILOpArg = B.getInt32(static_cast<unsigned>(DXILOp));
192  for (User *U : make_early_inc_range(F.users())) {
193  CallInst *CI = dyn_cast<CallInst>(U);
194  if (!CI)
195  continue;
196 
198  Args.emplace_back(DXILOpArg);
199  Args.append(CI->arg_begin(), CI->arg_end());
200  B.SetInsertPoint(CI);
201  CallInst *DXILCI = B.CreateCall(DXILOpFn, Args);
202  LLVM_DEBUG(DXILCI->setName(getOpCodeName(DXILOp)));
203  CI->replaceAllUsesWith(DXILCI);
204  CI->eraseFromParent();
205  }
206  if (F.user_empty())
207  F.eraseFromParent();
208 }
209 
210 static bool lowerIntrinsics(Module &M) {
211  bool Updated = false;
212 
213 #define DXIL_OP_INTRINSIC_MAP
214 #include "DXILOperation.inc"
215 #undef DXIL_OP_INTRINSIC_MAP
216 
217  for (Function &F : make_early_inc_range(M.functions())) {
218  if (!F.isDeclaration())
219  continue;
220  Intrinsic::ID ID = F.getIntrinsicID();
222  continue;
223  auto LowerIt = LowerMap.find(ID);
224  if (LowerIt == LowerMap.end())
225  continue;
226  lowerIntrinsic(LowerIt->second, F, M);
227  Updated = true;
228  }
229  return Updated;
230 }
231 
232 namespace {
233 /// A pass that transforms external global definitions into declarations.
234 class DXILOpLowering : public PassInfoMixin<DXILOpLowering> {
235 public:
237  if (lowerIntrinsics(M))
238  return PreservedAnalyses::none();
239  return PreservedAnalyses::all();
240  }
241 };
242 } // namespace
243 
244 namespace {
245 class DXILOpLoweringLegacy : public ModulePass {
246 public:
247  bool runOnModule(Module &M) override { return lowerIntrinsics(M); }
248  StringRef getPassName() const override { return "DXIL Op Lowering"; }
249  DXILOpLoweringLegacy() : ModulePass(ID) {}
250 
251  static char ID; // Pass identification.
252 };
253 char DXILOpLoweringLegacy::ID = 0;
254 
255 } // end anonymous namespace
256 
257 INITIALIZE_PASS_BEGIN(DXILOpLoweringLegacy, DEBUG_TYPE, "DXIL Op Lowering",
258  false, false)
259 INITIALIZE_PASS_END(DXILOpLoweringLegacy, DEBUG_TYPE, "DXIL Op Lowering", false,
260  false)
261 
263  return new DXILOpLoweringLegacy();
264 }
getOverloadKind
static OverloadKind getOverloadKind(Type *Ty)
Definition: DXILOpLowering.cpp:73
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:42
I64
@ I64
Definition: DXILOpLowering.cpp:41
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:158
LLVM_DEBUG
#define LLVM_DEBUG(X)
Definition: Debug.h:101
I1
@ I1
Definition: DXILOpLowering.cpp:37
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:139
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:4564
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:262
lowerIntrinsics
static bool lowerIntrinsics(Module &M)
Definition: DXILOpLowering.cpp:210
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:134
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:33
Passes.h
FLOAT
@ FLOAT
Definition: DXILOpLowering.cpp:35
OpCodeProperty
Definition: DXILOpLowering.cpp:131
OpCodeProperty::OpCodeClass
DXIL::OpCodeClass OpCodeClass
Definition: DXILOpLowering.cpp:135
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:259
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:30
IRBuilder.h
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
I16
@ I16
Definition: DXILOpLowering.cpp:39
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:43
getOverloadTypeName
static const char * getOverloadTypeName(OverloadKind Kind)
Definition: DXILOpLowering.cpp:46
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:34
OpCodeProperty::OverloadTys
uint16_t OverloadTys
Definition: DXILOpLowering.cpp:138
I32
@ I32
Definition: DXILOpLowering.cpp:40
OverloadKind
OverloadKind
Definition: DXILOpLowering.cpp:32
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:148
uint16_t
llvm::AMDGPU::SendMsg::Op
Op
Definition: SIDefines.h:345
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:132
PassManager.h
I8
@ I8
Definition: DXILOpLowering.cpp:38
DEBUG_TYPE
#define DEBUG_TYPE
Definition: DXILOpLowering.cpp:25
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:137
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:188
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:36
llvm::Intrinsic::ID
unsigned ID
Definition: TargetTransformInfo.h:38