LLVM  15.0.0git
SPIRVCallLowering.cpp
Go to the documentation of this file.
1 //===--- SPIRVCallLowering.cpp - Call lowering ------------------*- C++ -*-===//
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 // This file implements the lowering of LLVM calls to machine code calls for
10 // GlobalISel.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "SPIRVCallLowering.h"
16 #include "SPIRV.h"
17 #include "SPIRVGlobalRegistry.h"
18 #include "SPIRVISelLowering.h"
19 #include "SPIRVRegisterInfo.h"
20 #include "SPIRVSubtarget.h"
21 #include "SPIRVUtils.h"
23 
24 using namespace llvm;
25 
27  const SPIRVSubtarget &ST,
29  : CallLowering(&TLI), ST(ST), GR(GR) {}
30 
32  const Value *Val, ArrayRef<Register> VRegs,
34  Register SwiftErrorVReg) const {
35  // Currently all return types should use a single register.
36  // TODO: handle the case of multiple registers.
37  if (VRegs.size() > 1)
38  return false;
39  if (Val)
40  return MIRBuilder.buildInstr(SPIRV::OpReturnValue)
41  .addUse(VRegs[0])
42  .constrainAllUses(MIRBuilder.getTII(), *ST.getRegisterInfo(),
43  *ST.getRegBankInfo());
44  MIRBuilder.buildInstr(SPIRV::OpReturn);
45  return true;
46 }
47 
48 // Based on the LLVM function attributes, get a SPIR-V FunctionControl.
50  uint32_t FuncControl = static_cast<uint32_t>(SPIRV::FunctionControl::None);
51  if (F.hasFnAttribute(Attribute::AttrKind::AlwaysInline)) {
52  FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Inline);
53  }
54  if (F.hasFnAttribute(Attribute::AttrKind::ReadNone)) {
55  FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Pure);
56  }
57  if (F.hasFnAttribute(Attribute::AttrKind::ReadOnly)) {
58  FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Const);
59  }
60  if (F.hasFnAttribute(Attribute::AttrKind::NoInline)) {
61  FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::DontInline);
62  }
63  return FuncControl;
64 }
65 
67  const Function &F,
69  FunctionLoweringInfo &FLI) const {
70  assert(GR && "Must initialize the SPIRV type registry before lowering args.");
71 
72  // Assign types and names to all args, and store their types for later.
73  SmallVector<Register, 4> ArgTypeVRegs;
74  if (VRegs.size() > 0) {
75  unsigned i = 0;
76  for (const auto &Arg : F.args()) {
77  // Currently formal args should use single registers.
78  // TODO: handle the case of multiple registers.
79  if (VRegs[i].size() > 1)
80  return false;
81  auto *SpirvTy =
82  GR->assignTypeToVReg(Arg.getType(), VRegs[i][0], MIRBuilder);
83  ArgTypeVRegs.push_back(GR->getSPIRVTypeID(SpirvTy));
84 
85  if (Arg.hasName())
86  buildOpName(VRegs[i][0], Arg.getName(), MIRBuilder);
87  if (Arg.getType()->isPointerTy()) {
88  auto DerefBytes = static_cast<unsigned>(Arg.getDereferenceableBytes());
89  if (DerefBytes != 0)
90  buildOpDecorate(VRegs[i][0], MIRBuilder,
91  SPIRV::Decoration::MaxByteOffset, {DerefBytes});
92  }
93  if (Arg.hasAttribute(Attribute::Alignment)) {
94  buildOpDecorate(VRegs[i][0], MIRBuilder, SPIRV::Decoration::Alignment,
95  {static_cast<unsigned>(Arg.getParamAlignment())});
96  }
97  if (Arg.hasAttribute(Attribute::ReadOnly)) {
98  auto Attr =
99  static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoWrite);
100  buildOpDecorate(VRegs[i][0], MIRBuilder,
102  }
103  if (Arg.hasAttribute(Attribute::ZExt)) {
104  auto Attr =
105  static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Zext);
106  buildOpDecorate(VRegs[i][0], MIRBuilder,
108  }
109  ++i;
110  }
111  }
112 
113  // Generate a SPIR-V type for the function.
114  auto MRI = MIRBuilder.getMRI();
116  MRI->setRegClass(FuncVReg, &SPIRV::IDRegClass);
117 
118  auto *FTy = F.getFunctionType();
119  auto FuncTy = GR->assignTypeToVReg(FTy, FuncVReg, MIRBuilder);
120 
121  // Build the OpTypeFunction declaring it.
122  Register ReturnTypeID = FuncTy->getOperand(1).getReg();
123  uint32_t FuncControl = getFunctionControl(F);
124 
125  MIRBuilder.buildInstr(SPIRV::OpFunction)
126  .addDef(FuncVReg)
127  .addUse(ReturnTypeID)
128  .addImm(FuncControl)
129  .addUse(GR->getSPIRVTypeID(FuncTy));
130 
131  // Add OpFunctionParameters.
132  const unsigned NumArgs = ArgTypeVRegs.size();
133  for (unsigned i = 0; i < NumArgs; ++i) {
134  assert(VRegs[i].size() == 1 && "Formal arg has multiple vregs");
135  MRI->setRegClass(VRegs[i][0], &SPIRV::IDRegClass);
136  MIRBuilder.buildInstr(SPIRV::OpFunctionParameter)
137  .addDef(VRegs[i][0])
138  .addUse(ArgTypeVRegs[i]);
139  }
140  // Name the function.
141  if (F.hasName())
142  buildOpName(FuncVReg, F.getName(), MIRBuilder);
143 
144  // Handle entry points and function linkage.
145  if (F.getCallingConv() == CallingConv::SPIR_KERNEL) {
146  auto MIB = MIRBuilder.buildInstr(SPIRV::OpEntryPoint)
148  .addUse(FuncVReg);
149  addStringImm(F.getName(), MIB);
150  } else if (F.getLinkage() == GlobalValue::LinkageTypes::ExternalLinkage ||
151  F.getLinkage() == GlobalValue::LinkOnceODRLinkage) {
152  auto LnkTy = F.isDeclaration() ? SPIRV::LinkageType::Import
155  {static_cast<uint32_t>(LnkTy)}, F.getGlobalIdentifier());
156  }
157 
158  return true;
159 }
160 
162  CallLoweringInfo &Info) const {
163  // Currently call returns should have single vregs.
164  // TODO: handle the case of multiple registers.
165  if (Info.OrigRet.Regs.size() > 1)
166  return false;
167 
168  Register ResVReg =
169  Info.OrigRet.Regs.empty() ? Register(0) : Info.OrigRet.Regs[0];
170  // Emit a regular OpFunctionCall. If it's an externally declared function,
171  // be sure to emit its type and function declaration here. It will be
172  // hoisted globally later.
173  if (Info.Callee.isGlobal()) {
174  auto *CF = dyn_cast_or_null<const Function>(Info.Callee.getGlobal());
175  // TODO: support constexpr casts and indirect calls.
176  if (CF == nullptr)
177  return false;
178  if (CF->isDeclaration()) {
179  // Emit the type info and forward function declaration to the first MBB
180  // to ensure VReg definition dependencies are valid across all MBBs.
181  MachineBasicBlock::iterator OldII = MIRBuilder.getInsertPt();
182  MachineBasicBlock &OldBB = MIRBuilder.getMBB();
183  MachineBasicBlock &FirstBB = *MIRBuilder.getMF().getBlockNumbered(0);
184  MIRBuilder.setInsertPt(FirstBB, FirstBB.instr_end());
185 
186  SmallVector<ArrayRef<Register>, 8> VRegArgs;
188  for (const Argument &Arg : CF->args()) {
189  if (MIRBuilder.getDataLayout().getTypeStoreSize(Arg.getType()).isZero())
190  continue; // Don't handle zero sized types.
191  ToInsert.push_back({MIRBuilder.getMRI()->createGenericVirtualRegister(
192  LLT::scalar(32))});
193  VRegArgs.push_back(ToInsert.back());
194  }
195  // TODO: Reuse FunctionLoweringInfo.
196  FunctionLoweringInfo FuncInfo;
197  lowerFormalArguments(MIRBuilder, *CF, VRegArgs, FuncInfo);
198  MIRBuilder.setInsertPt(OldBB, OldII);
199  }
200  }
201 
202  // Make sure there's a valid return reg, even for functions returning void.
203  if (!ResVReg.isValid()) {
204  ResVReg = MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::IDRegClass);
205  }
206  SPIRVType *RetType =
207  GR->assignTypeToVReg(Info.OrigRet.Ty, ResVReg, MIRBuilder);
208 
209  // Emit the OpFunctionCall and its args.
210  auto MIB = MIRBuilder.buildInstr(SPIRV::OpFunctionCall)
211  .addDef(ResVReg)
212  .addUse(GR->getSPIRVTypeID(RetType))
213  .add(Info.Callee);
214 
215  for (const auto &Arg : Info.OrigArgs) {
216  // Currently call args should have single vregs.
217  if (Arg.Regs.size() > 1)
218  return false;
219  MIB.addUse(Arg.Regs[0]);
220  }
221  return MIB.constrainAllUses(MIRBuilder.getTII(), *ST.getRegisterInfo(),
222  *ST.getRegBankInfo());
223 }
i
i
Definition: README.txt:29
llvm::Argument
This class represents an incoming formal argument to a Function.
Definition: Argument.h:28
llvm::MachineInstrBuilder::addImm
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
Definition: MachineInstrBuilder.h:131
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
llvm::SPIRV::FunctionParameterAttribute::Zext
@ Zext
llvm::SPIRVCallLowering::lowerCall
bool lowerCall(MachineIRBuilder &MIRBuilder, CallLoweringInfo &Info) const override
This hook must be implemented to lower the given call instruction, including argument and return valu...
Definition: SPIRVCallLowering.cpp:161
llvm::SPIRV::ExecutionModel::Kernel
@ Kernel
SPIRVCallLowering.h
llvm::MachineRegisterInfo::createVirtualRegister
Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
Definition: MachineRegisterInfo.cpp:156
llvm::MachineInstrBuilder::add
const MachineInstrBuilder & add(const MachineOperand &MO) const
Definition: MachineInstrBuilder.h:224
llvm::Function
Definition: Function.h:60
getFunctionControl
static uint32_t getFunctionControl(const Function &F)
Definition: SPIRVCallLowering.cpp:49
llvm::SmallVector
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1185
llvm::MachineIRBuilder::getMRI
MachineRegisterInfo * getMRI()
Getter for MRI.
Definition: MachineIRBuilder.h:287
llvm::DataLayout::getTypeStoreSize
TypeSize getTypeStoreSize(Type *Ty) const
Returns the maximum number of bytes that may be overwritten by storing the specified type.
Definition: DataLayout.h:474
llvm::SPIRV::Decoration::FuncParamAttr
@ FuncParamAttr
llvm::SPIRVSubtarget
Definition: SPIRVSubtarget.h:36
SPIRVSubtarget.h
F
#define F(x, y, z)
Definition: MD5.cpp:55
Arg
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
Definition: AMDGPULibCalls.cpp:186
llvm::MachineInstrBuilder::addDef
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Definition: MachineInstrBuilder.h:116
FunctionLoweringInfo.h
SPIRVBaseInfo.h
llvm::SPIRV::LinkageType::Export
@ Export
llvm::SPIRV::LinkageType::Import
@ Import
llvm::MachineIRBuilder::getDataLayout
const DataLayout & getDataLayout() const
Definition: MachineIRBuilder.h:279
SPIRVRegisterInfo.h
llvm::MachineIRBuilder::getMF
MachineFunction & getMF()
Getter for the function we currently build.
Definition: MachineIRBuilder.h:269
SPIRVUtils.h
Info
Analysis containing CSE Info
Definition: CSEInfo.cpp:27
llvm::SPIRVCallLowering::lowerReturn
bool lowerReturn(MachineIRBuilder &MIRBuiler, const Value *Val, ArrayRef< Register > VRegs, FunctionLoweringInfo &FLI, Register SwiftErrorVReg) const override
This hook must be implemented to lower outgoing return values, described by Val, into the specified v...
Definition: SPIRVCallLowering.cpp:31
llvm::SPIRV::FunctionParameterAttribute::NoWrite
@ NoWrite
llvm::MachineBasicBlock
Definition: MachineBasicBlock.h:94
llvm::SPIRV::Decoration::LinkageAttributes
@ LinkageAttributes
addStringImm
void addStringImm(const StringRef &Str, MachineInstrBuilder &MIB)
Definition: SPIRVUtils.cpp:48
llvm::SPIRVSubtarget::getRegBankInfo
const RegisterBankInfo * getRegBankInfo() const override
Definition: SPIRVSubtarget.h:71
llvm::SPIRV::Decoration::Alignment
@ Alignment
llvm::SPIRV::FunctionControl::Inline
@ Inline
llvm::MachineIRBuilder::setInsertPt
void setInsertPt(MachineBasicBlock &MBB, MachineBasicBlock::iterator II)
Set the insertion point before the specified position.
Definition: MachineIRBuilder.h:313
llvm::MachineIRBuilder
Helper class to build MachineInstr.
Definition: MachineIRBuilder.h:219
llvm::MachineInstr
Representation of each machine instruction.
Definition: MachineInstr.h:66
SPIRVGlobalRegistry.h
llvm::ARM_MB::ST
@ ST
Definition: ARMBaseInfo.h:73
llvm::MachineIRBuilder::getInsertPt
MachineBasicBlock::iterator getInsertPt()
Current insertion point for new instructions.
Definition: MachineIRBuilder.h:308
llvm::SPIRV::FunctionControl::DontInline
@ DontInline
llvm::SPIRV::Decoration::MaxByteOffset
@ MaxByteOffset
SPIRV.h
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
SPIRVISelLowering.h
llvm::FunctionLoweringInfo
FunctionLoweringInfo - This contains information that is global to a function that is used when lower...
Definition: FunctionLoweringInfo.h:52
llvm::MachineIRBuilder::getMBB
const MachineBasicBlock & getMBB() const
Getter for the basic block we currently build.
Definition: MachineIRBuilder.h:294
llvm::SPIRVTargetLowering
Definition: SPIRVISelLowering.h:22
llvm::MachineRegisterInfo::createGenericVirtualRegister
Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
Definition: MachineRegisterInfo.cpp:186
llvm::SPIRVGlobalRegistry
Definition: SPIRVGlobalRegistry.h:26
buildOpDecorate
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, llvm::SPIRV::Decoration Dec, const std::vector< uint32_t > &DecArgs, StringRef StrImm)
Definition: SPIRVUtils.cpp:108
llvm::MachineInstrBuilder::addUse
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
Definition: MachineInstrBuilder.h:123
llvm::MachineInstrBuilder::constrainAllUses
bool constrainAllUses(const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const RegisterBankInfo &RBI) const
Definition: MachineInstrBuilder.h:320
llvm::MachineBasicBlock::instr_end
instr_iterator instr_end()
Definition: MachineBasicBlock.h:264
llvm::size
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition: STLExtras.h:1598
llvm::MachineIRBuilder::buildInstr
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
Definition: MachineIRBuilder.h:374
llvm::SPIRV::FunctionControl::Const
@ Const
llvm::ArrayRef
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: APInt.h:32
uint32_t
buildOpName
void buildOpName(Register Target, const StringRef &Name, MachineIRBuilder &MIRBuilder)
Definition: SPIRVUtils.cpp:91
MRI
unsigned const MachineRegisterInfo * MRI
Definition: AArch64AdvSIMDScalarPass.cpp:105
llvm::Register
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
llvm::MachineFunction::getBlockNumbered
MachineBasicBlock * getBlockNumbered(unsigned N) const
getBlockNumbered - MachineBasicBlocks are automatically numbered when they are inserted into the mach...
Definition: MachineFunction.h:788
llvm::SPIRV::FunctionControl::None
@ None
llvm::CallLowering::CallLoweringInfo
Definition: CallLowering.h:102
llvm::SPIRVGlobalRegistry::getSPIRVTypeID
Register getSPIRVTypeID(const SPIRVType *SpirvType) const
Definition: SPIRVGlobalRegistry.h:89
llvm::MachineIRBuilder::getTII
const TargetInstrInfo & getTII()
Definition: MachineIRBuilder.h:263
llvm::UnivariateLinearPolyBase::isZero
bool isZero() const
Definition: TypeSize.h:229
llvm::Register::isValid
bool isValid() const
Definition: Register.h:126
llvm::SPIRVGlobalRegistry::assignTypeToVReg
SPIRVType * assignTypeToVReg(const Type *Type, Register VReg, MachineIRBuilder &MIRBuilder, SPIRV::AccessQualifier AQ=SPIRV::AccessQualifier::ReadWrite, bool EmitIR=true)
Definition: SPIRVGlobalRegistry.cpp:27
llvm::ArrayRef::size
size_t size() const
size - Get the array size.
Definition: ArrayRef.h:164
llvm::SPIRVCallLowering::SPIRVCallLowering
SPIRVCallLowering(const SPIRVTargetLowering &TLI, const SPIRVSubtarget &ST, SPIRVGlobalRegistry *GR)
Definition: SPIRVCallLowering.cpp:26
llvm::CallingConv::SPIR_KERNEL
@ SPIR_KERNEL
SPIR_KERNEL - Calling convention for SPIR kernel functions.
Definition: CallingConv.h:152
llvm::SPIRVCallLowering::lowerFormalArguments
bool lowerFormalArguments(MachineIRBuilder &MIRBuilder, const Function &F, ArrayRef< ArrayRef< Register >> VRegs, FunctionLoweringInfo &FLI) const override
This hook must be implemented to lower the incoming (formal) arguments, described by VRegs,...
Definition: SPIRVCallLowering.cpp:66
llvm::GlobalValue::LinkOnceODRLinkage
@ LinkOnceODRLinkage
Same, but only replaced by something equivalent.
Definition: GlobalValue.h:51
llvm::MachineInstrBundleIterator< MachineInstr >
llvm::LLT::scalar
static LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
Definition: LowLevelTypeImpl.h:42
llvm::CallLowering
Definition: CallLowering.h:44
llvm::Value
LLVM Value Representation.
Definition: Value.h:74
llvm::MachineRegisterInfo::setRegClass
void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
Definition: MachineRegisterInfo.cpp:56
llvm::SPIRVSubtarget::getRegisterInfo
const SPIRVRegisterInfo * getRegisterInfo() const override
Definition: SPIRVSubtarget.h:87
llvm::SPIRV::FunctionControl::Pure
@ Pure