181ad6265SDimitry Andric //===--- SPIRVCallLowering.cpp - Call lowering ------------------*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric // 981ad6265SDimitry Andric // This file implements the lowering of LLVM calls to machine code calls for 1081ad6265SDimitry Andric // GlobalISel. 1181ad6265SDimitry Andric // 1281ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1381ad6265SDimitry Andric 1481ad6265SDimitry Andric #include "SPIRVCallLowering.h" 1581ad6265SDimitry Andric #include "MCTargetDesc/SPIRVBaseInfo.h" 1681ad6265SDimitry Andric #include "SPIRV.h" 17bdd1243dSDimitry Andric #include "SPIRVBuiltins.h" 1881ad6265SDimitry Andric #include "SPIRVGlobalRegistry.h" 1981ad6265SDimitry Andric #include "SPIRVISelLowering.h" 20*0fca6ea1SDimitry Andric #include "SPIRVMetadata.h" 2181ad6265SDimitry Andric #include "SPIRVRegisterInfo.h" 2281ad6265SDimitry Andric #include "SPIRVSubtarget.h" 2381ad6265SDimitry Andric #include "SPIRVUtils.h" 2481ad6265SDimitry Andric #include "llvm/CodeGen/FunctionLoweringInfo.h" 25*0fca6ea1SDimitry Andric #include "llvm/IR/IntrinsicInst.h" 26*0fca6ea1SDimitry Andric #include "llvm/IR/IntrinsicsSPIRV.h" 27bdd1243dSDimitry Andric #include "llvm/Support/ModRef.h" 2881ad6265SDimitry Andric 2981ad6265SDimitry Andric using namespace llvm; 3081ad6265SDimitry Andric 3181ad6265SDimitry Andric SPIRVCallLowering::SPIRVCallLowering(const SPIRVTargetLowering &TLI, 3281ad6265SDimitry Andric SPIRVGlobalRegistry *GR) 33fcaf7f86SDimitry Andric : CallLowering(&TLI), GR(GR) {} 3481ad6265SDimitry Andric 3581ad6265SDimitry Andric bool SPIRVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, 3681ad6265SDimitry Andric const Value *Val, ArrayRef<Register> VRegs, 3781ad6265SDimitry Andric FunctionLoweringInfo &FLI, 3881ad6265SDimitry Andric Register SwiftErrorVReg) const { 39*0fca6ea1SDimitry Andric // Maybe run postponed production of types for function pointers 40*0fca6ea1SDimitry Andric if (IndirectCalls.size() > 0) { 41*0fca6ea1SDimitry Andric produceIndirectPtrTypes(MIRBuilder); 42*0fca6ea1SDimitry Andric IndirectCalls.clear(); 43*0fca6ea1SDimitry Andric } 44*0fca6ea1SDimitry Andric 4581ad6265SDimitry Andric // Currently all return types should use a single register. 4681ad6265SDimitry Andric // TODO: handle the case of multiple registers. 4781ad6265SDimitry Andric if (VRegs.size() > 1) 4881ad6265SDimitry Andric return false; 49fcaf7f86SDimitry Andric if (Val) { 50fcaf7f86SDimitry Andric const auto &STI = MIRBuilder.getMF().getSubtarget(); 5181ad6265SDimitry Andric return MIRBuilder.buildInstr(SPIRV::OpReturnValue) 5281ad6265SDimitry Andric .addUse(VRegs[0]) 53fcaf7f86SDimitry Andric .constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(), 54fcaf7f86SDimitry Andric *STI.getRegBankInfo()); 55fcaf7f86SDimitry Andric } 5681ad6265SDimitry Andric MIRBuilder.buildInstr(SPIRV::OpReturn); 5781ad6265SDimitry Andric return true; 5881ad6265SDimitry Andric } 5981ad6265SDimitry Andric 6081ad6265SDimitry Andric // Based on the LLVM function attributes, get a SPIR-V FunctionControl. 6181ad6265SDimitry Andric static uint32_t getFunctionControl(const Function &F) { 62bdd1243dSDimitry Andric MemoryEffects MemEffects = F.getMemoryEffects(); 63bdd1243dSDimitry Andric 6481ad6265SDimitry Andric uint32_t FuncControl = static_cast<uint32_t>(SPIRV::FunctionControl::None); 65bdd1243dSDimitry Andric 66bdd1243dSDimitry Andric if (F.hasFnAttribute(Attribute::AttrKind::NoInline)) 6781ad6265SDimitry Andric FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::DontInline); 68bdd1243dSDimitry Andric else if (F.hasFnAttribute(Attribute::AttrKind::AlwaysInline)) 69bdd1243dSDimitry Andric FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Inline); 70bdd1243dSDimitry Andric 71bdd1243dSDimitry Andric if (MemEffects.doesNotAccessMemory()) 72bdd1243dSDimitry Andric FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Pure); 73bdd1243dSDimitry Andric else if (MemEffects.onlyReadsMemory()) 74bdd1243dSDimitry Andric FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Const); 75bdd1243dSDimitry Andric 7681ad6265SDimitry Andric return FuncControl; 7781ad6265SDimitry Andric } 7881ad6265SDimitry Andric 79fcaf7f86SDimitry Andric static ConstantInt *getConstInt(MDNode *MD, unsigned NumOp) { 80fcaf7f86SDimitry Andric if (MD->getNumOperands() > NumOp) { 81fcaf7f86SDimitry Andric auto *CMeta = dyn_cast<ConstantAsMetadata>(MD->getOperand(NumOp)); 82fcaf7f86SDimitry Andric if (CMeta) 83fcaf7f86SDimitry Andric return dyn_cast<ConstantInt>(CMeta->getValue()); 84fcaf7f86SDimitry Andric } 85fcaf7f86SDimitry Andric return nullptr; 86fcaf7f86SDimitry Andric } 87fcaf7f86SDimitry Andric 88*0fca6ea1SDimitry Andric // If the function has pointer arguments, we are forced to re-create this 89*0fca6ea1SDimitry Andric // function type from the very beginning, changing PointerType by 90*0fca6ea1SDimitry Andric // TypedPointerType for each pointer argument. Otherwise, the same `Type*` 91*0fca6ea1SDimitry Andric // potentially corresponds to different SPIR-V function type, effectively 92*0fca6ea1SDimitry Andric // invalidating logic behind global registry and duplicates tracker. 93*0fca6ea1SDimitry Andric static FunctionType * 94*0fca6ea1SDimitry Andric fixFunctionTypeIfPtrArgs(SPIRVGlobalRegistry *GR, const Function &F, 95*0fca6ea1SDimitry Andric FunctionType *FTy, const SPIRVType *SRetTy, 96*0fca6ea1SDimitry Andric const SmallVector<SPIRVType *, 4> &SArgTys) { 97*0fca6ea1SDimitry Andric if (F.getParent()->getNamedMetadata("spv.cloned_funcs")) 98*0fca6ea1SDimitry Andric return FTy; 99*0fca6ea1SDimitry Andric 100*0fca6ea1SDimitry Andric bool hasArgPtrs = false; 101*0fca6ea1SDimitry Andric for (auto &Arg : F.args()) { 102*0fca6ea1SDimitry Andric // check if it's an instance of a non-typed PointerType 103*0fca6ea1SDimitry Andric if (Arg.getType()->isPointerTy()) { 104*0fca6ea1SDimitry Andric hasArgPtrs = true; 105*0fca6ea1SDimitry Andric break; 106*0fca6ea1SDimitry Andric } 107*0fca6ea1SDimitry Andric } 108*0fca6ea1SDimitry Andric if (!hasArgPtrs) { 109*0fca6ea1SDimitry Andric Type *RetTy = FTy->getReturnType(); 110*0fca6ea1SDimitry Andric // check if it's an instance of a non-typed PointerType 111*0fca6ea1SDimitry Andric if (!RetTy->isPointerTy()) 112*0fca6ea1SDimitry Andric return FTy; 113*0fca6ea1SDimitry Andric } 114*0fca6ea1SDimitry Andric 115*0fca6ea1SDimitry Andric // re-create function type, using TypedPointerType instead of PointerType to 116*0fca6ea1SDimitry Andric // properly trace argument types 117*0fca6ea1SDimitry Andric const Type *RetTy = GR->getTypeForSPIRVType(SRetTy); 118*0fca6ea1SDimitry Andric SmallVector<Type *, 4> ArgTys; 119*0fca6ea1SDimitry Andric for (auto SArgTy : SArgTys) 120*0fca6ea1SDimitry Andric ArgTys.push_back(const_cast<Type *>(GR->getTypeForSPIRVType(SArgTy))); 121*0fca6ea1SDimitry Andric return FunctionType::get(const_cast<Type *>(RetTy), ArgTys, false); 122*0fca6ea1SDimitry Andric } 123*0fca6ea1SDimitry Andric 124fcaf7f86SDimitry Andric // This code restores function args/retvalue types for composite cases 125fcaf7f86SDimitry Andric // because the final types should still be aggregate whereas they're i32 126fcaf7f86SDimitry Andric // during the translation to cope with aggregate flattening etc. 127fcaf7f86SDimitry Andric static FunctionType *getOriginalFunctionType(const Function &F) { 128fcaf7f86SDimitry Andric auto *NamedMD = F.getParent()->getNamedMetadata("spv.cloned_funcs"); 129fcaf7f86SDimitry Andric if (NamedMD == nullptr) 130fcaf7f86SDimitry Andric return F.getFunctionType(); 131fcaf7f86SDimitry Andric 132fcaf7f86SDimitry Andric Type *RetTy = F.getFunctionType()->getReturnType(); 133fcaf7f86SDimitry Andric SmallVector<Type *, 4> ArgTypes; 134fcaf7f86SDimitry Andric for (auto &Arg : F.args()) 135fcaf7f86SDimitry Andric ArgTypes.push_back(Arg.getType()); 136fcaf7f86SDimitry Andric 137fcaf7f86SDimitry Andric auto ThisFuncMDIt = 138fcaf7f86SDimitry Andric std::find_if(NamedMD->op_begin(), NamedMD->op_end(), [&F](MDNode *N) { 139fcaf7f86SDimitry Andric return isa<MDString>(N->getOperand(0)) && 140fcaf7f86SDimitry Andric cast<MDString>(N->getOperand(0))->getString() == F.getName(); 141fcaf7f86SDimitry Andric }); 142fcaf7f86SDimitry Andric // TODO: probably one function can have numerous type mutations, 143fcaf7f86SDimitry Andric // so we should support this. 144fcaf7f86SDimitry Andric if (ThisFuncMDIt != NamedMD->op_end()) { 145fcaf7f86SDimitry Andric auto *ThisFuncMD = *ThisFuncMDIt; 146fcaf7f86SDimitry Andric MDNode *MD = dyn_cast<MDNode>(ThisFuncMD->getOperand(1)); 147fcaf7f86SDimitry Andric assert(MD && "MDNode operand is expected"); 148fcaf7f86SDimitry Andric ConstantInt *Const = getConstInt(MD, 0); 149fcaf7f86SDimitry Andric if (Const) { 150fcaf7f86SDimitry Andric auto *CMeta = dyn_cast<ConstantAsMetadata>(MD->getOperand(1)); 151fcaf7f86SDimitry Andric assert(CMeta && "ConstantAsMetadata operand is expected"); 152fcaf7f86SDimitry Andric assert(Const->getSExtValue() >= -1); 153fcaf7f86SDimitry Andric // Currently -1 indicates return value, greater values mean 154fcaf7f86SDimitry Andric // argument numbers. 155fcaf7f86SDimitry Andric if (Const->getSExtValue() == -1) 156fcaf7f86SDimitry Andric RetTy = CMeta->getType(); 157fcaf7f86SDimitry Andric else 158fcaf7f86SDimitry Andric ArgTypes[Const->getSExtValue()] = CMeta->getType(); 159fcaf7f86SDimitry Andric } 160fcaf7f86SDimitry Andric } 161fcaf7f86SDimitry Andric 162fcaf7f86SDimitry Andric return FunctionType::get(RetTy, ArgTypes, F.isVarArg()); 163fcaf7f86SDimitry Andric } 164fcaf7f86SDimitry Andric 165bdd1243dSDimitry Andric static SPIRV::AccessQualifier::AccessQualifier 166bdd1243dSDimitry Andric getArgAccessQual(const Function &F, unsigned ArgIdx) { 167bdd1243dSDimitry Andric if (F.getCallingConv() != CallingConv::SPIR_KERNEL) 168bdd1243dSDimitry Andric return SPIRV::AccessQualifier::ReadWrite; 169bdd1243dSDimitry Andric 170*0fca6ea1SDimitry Andric MDString *ArgAttribute = getOCLKernelArgAccessQual(F, ArgIdx); 171bdd1243dSDimitry Andric if (!ArgAttribute) 172bdd1243dSDimitry Andric return SPIRV::AccessQualifier::ReadWrite; 173bdd1243dSDimitry Andric 174*0fca6ea1SDimitry Andric if (ArgAttribute->getString() == "read_only") 175bdd1243dSDimitry Andric return SPIRV::AccessQualifier::ReadOnly; 176*0fca6ea1SDimitry Andric if (ArgAttribute->getString() == "write_only") 177bdd1243dSDimitry Andric return SPIRV::AccessQualifier::WriteOnly; 178bdd1243dSDimitry Andric return SPIRV::AccessQualifier::ReadWrite; 179bdd1243dSDimitry Andric } 180bdd1243dSDimitry Andric 181bdd1243dSDimitry Andric static std::vector<SPIRV::Decoration::Decoration> 182*0fca6ea1SDimitry Andric getKernelArgTypeQual(const Function &F, unsigned ArgIdx) { 183*0fca6ea1SDimitry Andric MDString *ArgAttribute = getOCLKernelArgTypeQual(F, ArgIdx); 184*0fca6ea1SDimitry Andric if (ArgAttribute && ArgAttribute->getString() == "volatile") 185bdd1243dSDimitry Andric return {SPIRV::Decoration::Volatile}; 186bdd1243dSDimitry Andric return {}; 187bdd1243dSDimitry Andric } 188bdd1243dSDimitry Andric 1895f757f3fSDimitry Andric static SPIRVType *getArgSPIRVType(const Function &F, unsigned ArgIdx, 1905f757f3fSDimitry Andric SPIRVGlobalRegistry *GR, 191*0fca6ea1SDimitry Andric MachineIRBuilder &MIRBuilder, 192*0fca6ea1SDimitry Andric const SPIRVSubtarget &ST) { 1935f757f3fSDimitry Andric // Read argument's access qualifier from metadata or default. 1945f757f3fSDimitry Andric SPIRV::AccessQualifier::AccessQualifier ArgAccessQual = 1955f757f3fSDimitry Andric getArgAccessQual(F, ArgIdx); 1965f757f3fSDimitry Andric 197bdd1243dSDimitry Andric Type *OriginalArgType = getOriginalFunctionType(F)->getParamType(ArgIdx); 1985f757f3fSDimitry Andric 199*0fca6ea1SDimitry Andric // If OriginalArgType is non-pointer, use the OriginalArgType (the type cannot 200*0fca6ea1SDimitry Andric // be legally reassigned later). 201*0fca6ea1SDimitry Andric if (!isPointerTy(OriginalArgType)) 2025f757f3fSDimitry Andric return GR->getOrCreateSPIRVType(OriginalArgType, MIRBuilder, ArgAccessQual); 203bdd1243dSDimitry Andric 204*0fca6ea1SDimitry Andric Argument *Arg = F.getArg(ArgIdx); 205*0fca6ea1SDimitry Andric Type *ArgType = Arg->getType(); 206*0fca6ea1SDimitry Andric if (isTypedPointerTy(ArgType)) { 207*0fca6ea1SDimitry Andric SPIRVType *ElementType = GR->getOrCreateSPIRVType( 208*0fca6ea1SDimitry Andric cast<TypedPointerType>(ArgType)->getElementType(), MIRBuilder); 209*0fca6ea1SDimitry Andric return GR->getOrCreateSPIRVPointerType( 210*0fca6ea1SDimitry Andric ElementType, MIRBuilder, 211*0fca6ea1SDimitry Andric addressSpaceToStorageClass(getPointerAddressSpace(ArgType), ST)); 2125f757f3fSDimitry Andric } 2135f757f3fSDimitry Andric 214*0fca6ea1SDimitry Andric // In case OriginalArgType is of untyped pointer type, there are three 215*0fca6ea1SDimitry Andric // possibilities: 216*0fca6ea1SDimitry Andric // 1) This is a pointer of an LLVM IR element type, passed byval/byref. 217*0fca6ea1SDimitry Andric // 2) This is an OpenCL/SPIR-V builtin type if there is spv_assign_type 218*0fca6ea1SDimitry Andric // intrinsic assigning a TargetExtType. 219*0fca6ea1SDimitry Andric // 3) This is a pointer, try to retrieve pointer element type from a 220*0fca6ea1SDimitry Andric // spv_assign_ptr_type intrinsic or otherwise use default pointer element 221*0fca6ea1SDimitry Andric // type. 222*0fca6ea1SDimitry Andric if (hasPointeeTypeAttr(Arg)) { 223*0fca6ea1SDimitry Andric SPIRVType *ElementType = 224*0fca6ea1SDimitry Andric GR->getOrCreateSPIRVType(getPointeeTypeByAttr(Arg), MIRBuilder); 225*0fca6ea1SDimitry Andric return GR->getOrCreateSPIRVPointerType( 226*0fca6ea1SDimitry Andric ElementType, MIRBuilder, 227*0fca6ea1SDimitry Andric addressSpaceToStorageClass(getPointerAddressSpace(ArgType), ST)); 228*0fca6ea1SDimitry Andric } 2295f757f3fSDimitry Andric 230*0fca6ea1SDimitry Andric for (auto User : Arg->users()) { 231*0fca6ea1SDimitry Andric auto *II = dyn_cast<IntrinsicInst>(User); 232*0fca6ea1SDimitry Andric // Check if this is spv_assign_type assigning OpenCL/SPIR-V builtin type. 233*0fca6ea1SDimitry Andric if (II && II->getIntrinsicID() == Intrinsic::spv_assign_type) { 234*0fca6ea1SDimitry Andric MetadataAsValue *VMD = cast<MetadataAsValue>(II->getOperand(1)); 235*0fca6ea1SDimitry Andric Type *BuiltinType = 236*0fca6ea1SDimitry Andric cast<ConstantAsMetadata>(VMD->getMetadata())->getType(); 237*0fca6ea1SDimitry Andric assert(BuiltinType->isTargetExtTy() && "Expected TargetExtType"); 238*0fca6ea1SDimitry Andric return GR->getOrCreateSPIRVType(BuiltinType, MIRBuilder, ArgAccessQual); 239*0fca6ea1SDimitry Andric } 2405f757f3fSDimitry Andric 241*0fca6ea1SDimitry Andric // Check if this is spv_assign_ptr_type assigning pointer element type. 242*0fca6ea1SDimitry Andric if (!II || II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type) 243*0fca6ea1SDimitry Andric continue; 244*0fca6ea1SDimitry Andric 245*0fca6ea1SDimitry Andric MetadataAsValue *VMD = cast<MetadataAsValue>(II->getOperand(1)); 246*0fca6ea1SDimitry Andric Type *ElementTy = 247*0fca6ea1SDimitry Andric toTypedPointer(cast<ConstantAsMetadata>(VMD->getMetadata())->getType()); 248*0fca6ea1SDimitry Andric SPIRVType *ElementType = GR->getOrCreateSPIRVType(ElementTy, MIRBuilder); 249*0fca6ea1SDimitry Andric return GR->getOrCreateSPIRVPointerType( 250*0fca6ea1SDimitry Andric ElementType, MIRBuilder, 251*0fca6ea1SDimitry Andric addressSpaceToStorageClass( 252*0fca6ea1SDimitry Andric cast<ConstantInt>(II->getOperand(2))->getZExtValue(), ST)); 253*0fca6ea1SDimitry Andric } 254*0fca6ea1SDimitry Andric 255*0fca6ea1SDimitry Andric // Replace PointerType with TypedPointerType to be able to map SPIR-V types to 256*0fca6ea1SDimitry Andric // LLVM types in a consistent manner 257*0fca6ea1SDimitry Andric return GR->getOrCreateSPIRVType(toTypedPointer(OriginalArgType), MIRBuilder, 258*0fca6ea1SDimitry Andric ArgAccessQual); 2595f757f3fSDimitry Andric } 2605f757f3fSDimitry Andric 2615f757f3fSDimitry Andric static SPIRV::ExecutionModel::ExecutionModel 2625f757f3fSDimitry Andric getExecutionModel(const SPIRVSubtarget &STI, const Function &F) { 2635f757f3fSDimitry Andric if (STI.isOpenCLEnv()) 2645f757f3fSDimitry Andric return SPIRV::ExecutionModel::Kernel; 2655f757f3fSDimitry Andric 2665f757f3fSDimitry Andric auto attribute = F.getFnAttribute("hlsl.shader"); 2675f757f3fSDimitry Andric if (!attribute.isValid()) { 2685f757f3fSDimitry Andric report_fatal_error( 2695f757f3fSDimitry Andric "This entry point lacks mandatory hlsl.shader attribute."); 2705f757f3fSDimitry Andric } 2715f757f3fSDimitry Andric 2725f757f3fSDimitry Andric const auto value = attribute.getValueAsString(); 2735f757f3fSDimitry Andric if (value == "compute") 2745f757f3fSDimitry Andric return SPIRV::ExecutionModel::GLCompute; 2755f757f3fSDimitry Andric 2765f757f3fSDimitry Andric report_fatal_error("This HLSL entry point is not supported by this backend."); 277bdd1243dSDimitry Andric } 278bdd1243dSDimitry Andric 27981ad6265SDimitry Andric bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder, 28081ad6265SDimitry Andric const Function &F, 28181ad6265SDimitry Andric ArrayRef<ArrayRef<Register>> VRegs, 28281ad6265SDimitry Andric FunctionLoweringInfo &FLI) const { 28381ad6265SDimitry Andric assert(GR && "Must initialize the SPIRV type registry before lowering args."); 284753f127fSDimitry Andric GR->setCurrentFunc(MIRBuilder.getMF()); 28581ad6265SDimitry Andric 286*0fca6ea1SDimitry Andric // Get access to information about available extensions 287*0fca6ea1SDimitry Andric const SPIRVSubtarget *ST = 288*0fca6ea1SDimitry Andric static_cast<const SPIRVSubtarget *>(&MIRBuilder.getMF().getSubtarget()); 289*0fca6ea1SDimitry Andric 29081ad6265SDimitry Andric // Assign types and names to all args, and store their types for later. 291fcaf7f86SDimitry Andric SmallVector<SPIRVType *, 4> ArgTypeVRegs; 29281ad6265SDimitry Andric if (VRegs.size() > 0) { 29381ad6265SDimitry Andric unsigned i = 0; 29481ad6265SDimitry Andric for (const auto &Arg : F.args()) { 29581ad6265SDimitry Andric // Currently formal args should use single registers. 29681ad6265SDimitry Andric // TODO: handle the case of multiple registers. 29781ad6265SDimitry Andric if (VRegs[i].size() > 1) 29881ad6265SDimitry Andric return false; 299*0fca6ea1SDimitry Andric auto *SpirvTy = getArgSPIRVType(F, i, GR, MIRBuilder, *ST); 3005f757f3fSDimitry Andric GR->assignSPIRVTypeToVReg(SpirvTy, VRegs[i][0], MIRBuilder.getMF()); 301fcaf7f86SDimitry Andric ArgTypeVRegs.push_back(SpirvTy); 30281ad6265SDimitry Andric 30381ad6265SDimitry Andric if (Arg.hasName()) 30481ad6265SDimitry Andric buildOpName(VRegs[i][0], Arg.getName(), MIRBuilder); 305*0fca6ea1SDimitry Andric if (isPointerTy(Arg.getType())) { 30681ad6265SDimitry Andric auto DerefBytes = static_cast<unsigned>(Arg.getDereferenceableBytes()); 30781ad6265SDimitry Andric if (DerefBytes != 0) 30881ad6265SDimitry Andric buildOpDecorate(VRegs[i][0], MIRBuilder, 30981ad6265SDimitry Andric SPIRV::Decoration::MaxByteOffset, {DerefBytes}); 31081ad6265SDimitry Andric } 31181ad6265SDimitry Andric if (Arg.hasAttribute(Attribute::Alignment)) { 312fcaf7f86SDimitry Andric auto Alignment = static_cast<unsigned>( 313fcaf7f86SDimitry Andric Arg.getAttribute(Attribute::Alignment).getValueAsInt()); 31481ad6265SDimitry Andric buildOpDecorate(VRegs[i][0], MIRBuilder, SPIRV::Decoration::Alignment, 315fcaf7f86SDimitry Andric {Alignment}); 31681ad6265SDimitry Andric } 31781ad6265SDimitry Andric if (Arg.hasAttribute(Attribute::ReadOnly)) { 31881ad6265SDimitry Andric auto Attr = 31981ad6265SDimitry Andric static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoWrite); 32081ad6265SDimitry Andric buildOpDecorate(VRegs[i][0], MIRBuilder, 32181ad6265SDimitry Andric SPIRV::Decoration::FuncParamAttr, {Attr}); 32281ad6265SDimitry Andric } 32381ad6265SDimitry Andric if (Arg.hasAttribute(Attribute::ZExt)) { 32481ad6265SDimitry Andric auto Attr = 32581ad6265SDimitry Andric static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Zext); 32681ad6265SDimitry Andric buildOpDecorate(VRegs[i][0], MIRBuilder, 32781ad6265SDimitry Andric SPIRV::Decoration::FuncParamAttr, {Attr}); 32881ad6265SDimitry Andric } 329fcaf7f86SDimitry Andric if (Arg.hasAttribute(Attribute::NoAlias)) { 330fcaf7f86SDimitry Andric auto Attr = 331fcaf7f86SDimitry Andric static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoAlias); 332fcaf7f86SDimitry Andric buildOpDecorate(VRegs[i][0], MIRBuilder, 333fcaf7f86SDimitry Andric SPIRV::Decoration::FuncParamAttr, {Attr}); 334fcaf7f86SDimitry Andric } 335*0fca6ea1SDimitry Andric if (Arg.hasAttribute(Attribute::ByVal)) { 336*0fca6ea1SDimitry Andric auto Attr = 337*0fca6ea1SDimitry Andric static_cast<unsigned>(SPIRV::FunctionParameterAttribute::ByVal); 338*0fca6ea1SDimitry Andric buildOpDecorate(VRegs[i][0], MIRBuilder, 339*0fca6ea1SDimitry Andric SPIRV::Decoration::FuncParamAttr, {Attr}); 340*0fca6ea1SDimitry Andric } 341bdd1243dSDimitry Andric 342bdd1243dSDimitry Andric if (F.getCallingConv() == CallingConv::SPIR_KERNEL) { 343bdd1243dSDimitry Andric std::vector<SPIRV::Decoration::Decoration> ArgTypeQualDecs = 344bdd1243dSDimitry Andric getKernelArgTypeQual(F, i); 345bdd1243dSDimitry Andric for (SPIRV::Decoration::Decoration Decoration : ArgTypeQualDecs) 346bdd1243dSDimitry Andric buildOpDecorate(VRegs[i][0], MIRBuilder, Decoration, {}); 347fcaf7f86SDimitry Andric } 348bdd1243dSDimitry Andric 349bdd1243dSDimitry Andric MDNode *Node = F.getMetadata("spirv.ParameterDecorations"); 350fcaf7f86SDimitry Andric if (Node && i < Node->getNumOperands() && 351fcaf7f86SDimitry Andric isa<MDNode>(Node->getOperand(i))) { 352fcaf7f86SDimitry Andric MDNode *MD = cast<MDNode>(Node->getOperand(i)); 353fcaf7f86SDimitry Andric for (const MDOperand &MDOp : MD->operands()) { 354fcaf7f86SDimitry Andric MDNode *MD2 = dyn_cast<MDNode>(MDOp); 355fcaf7f86SDimitry Andric assert(MD2 && "Metadata operand is expected"); 356fcaf7f86SDimitry Andric ConstantInt *Const = getConstInt(MD2, 0); 357fcaf7f86SDimitry Andric assert(Const && "MDOperand should be ConstantInt"); 358bdd1243dSDimitry Andric auto Dec = 359bdd1243dSDimitry Andric static_cast<SPIRV::Decoration::Decoration>(Const->getZExtValue()); 360fcaf7f86SDimitry Andric std::vector<uint32_t> DecVec; 361fcaf7f86SDimitry Andric for (unsigned j = 1; j < MD2->getNumOperands(); j++) { 362fcaf7f86SDimitry Andric ConstantInt *Const = getConstInt(MD2, j); 363fcaf7f86SDimitry Andric assert(Const && "MDOperand should be ConstantInt"); 364fcaf7f86SDimitry Andric DecVec.push_back(static_cast<uint32_t>(Const->getZExtValue())); 365fcaf7f86SDimitry Andric } 366fcaf7f86SDimitry Andric buildOpDecorate(VRegs[i][0], MIRBuilder, Dec, DecVec); 367fcaf7f86SDimitry Andric } 368fcaf7f86SDimitry Andric } 36981ad6265SDimitry Andric ++i; 37081ad6265SDimitry Andric } 37181ad6265SDimitry Andric } 37281ad6265SDimitry Andric 37381ad6265SDimitry Andric auto MRI = MIRBuilder.getMRI(); 37481ad6265SDimitry Andric Register FuncVReg = MRI->createGenericVirtualRegister(LLT::scalar(32)); 37581ad6265SDimitry Andric MRI->setRegClass(FuncVReg, &SPIRV::IDRegClass); 376753f127fSDimitry Andric if (F.isDeclaration()) 377753f127fSDimitry Andric GR->add(&F, &MIRBuilder.getMF(), FuncVReg); 378*0fca6ea1SDimitry Andric FunctionType *FTy = getOriginalFunctionType(F); 379*0fca6ea1SDimitry Andric Type *FRetTy = FTy->getReturnType(); 380*0fca6ea1SDimitry Andric if (isUntypedPointerTy(FRetTy)) { 381*0fca6ea1SDimitry Andric if (Type *FRetElemTy = GR->findDeducedElementType(&F)) { 382*0fca6ea1SDimitry Andric TypedPointerType *DerivedTy = TypedPointerType::get( 383*0fca6ea1SDimitry Andric toTypedPointer(FRetElemTy), getPointerAddressSpace(FRetTy)); 384*0fca6ea1SDimitry Andric GR->addReturnType(&F, DerivedTy); 385*0fca6ea1SDimitry Andric FRetTy = DerivedTy; 386*0fca6ea1SDimitry Andric } 387*0fca6ea1SDimitry Andric } 388*0fca6ea1SDimitry Andric SPIRVType *RetTy = GR->getOrCreateSPIRVType(FRetTy, MIRBuilder); 389*0fca6ea1SDimitry Andric FTy = fixFunctionTypeIfPtrArgs(GR, F, FTy, RetTy, ArgTypeVRegs); 390fcaf7f86SDimitry Andric SPIRVType *FuncTy = GR->getOrCreateOpTypeFunctionWithArgs( 391fcaf7f86SDimitry Andric FTy, RetTy, ArgTypeVRegs, MIRBuilder); 39281ad6265SDimitry Andric uint32_t FuncControl = getFunctionControl(F); 39381ad6265SDimitry Andric 394*0fca6ea1SDimitry Andric // Add OpFunction instruction 395*0fca6ea1SDimitry Andric MachineInstrBuilder MB = MIRBuilder.buildInstr(SPIRV::OpFunction) 39681ad6265SDimitry Andric .addDef(FuncVReg) 397fcaf7f86SDimitry Andric .addUse(GR->getSPIRVTypeID(RetTy)) 39881ad6265SDimitry Andric .addImm(FuncControl) 39981ad6265SDimitry Andric .addUse(GR->getSPIRVTypeID(FuncTy)); 400*0fca6ea1SDimitry Andric GR->recordFunctionDefinition(&F, &MB.getInstr()->getOperand(0)); 40181ad6265SDimitry Andric 402*0fca6ea1SDimitry Andric // Add OpFunctionParameter instructions 403fcaf7f86SDimitry Andric int i = 0; 404fcaf7f86SDimitry Andric for (const auto &Arg : F.args()) { 40581ad6265SDimitry Andric assert(VRegs[i].size() == 1 && "Formal arg has multiple vregs"); 40681ad6265SDimitry Andric MRI->setRegClass(VRegs[i][0], &SPIRV::IDRegClass); 40781ad6265SDimitry Andric MIRBuilder.buildInstr(SPIRV::OpFunctionParameter) 40881ad6265SDimitry Andric .addDef(VRegs[i][0]) 409fcaf7f86SDimitry Andric .addUse(GR->getSPIRVTypeID(ArgTypeVRegs[i])); 410753f127fSDimitry Andric if (F.isDeclaration()) 411fcaf7f86SDimitry Andric GR->add(&Arg, &MIRBuilder.getMF(), VRegs[i][0]); 412fcaf7f86SDimitry Andric i++; 41381ad6265SDimitry Andric } 41481ad6265SDimitry Andric // Name the function. 41581ad6265SDimitry Andric if (F.hasName()) 41681ad6265SDimitry Andric buildOpName(FuncVReg, F.getName(), MIRBuilder); 41781ad6265SDimitry Andric 41881ad6265SDimitry Andric // Handle entry points and function linkage. 4195f757f3fSDimitry Andric if (isEntryPoint(F)) { 4205f757f3fSDimitry Andric const auto &STI = MIRBuilder.getMF().getSubtarget<SPIRVSubtarget>(); 4215f757f3fSDimitry Andric auto executionModel = getExecutionModel(STI, F); 42281ad6265SDimitry Andric auto MIB = MIRBuilder.buildInstr(SPIRV::OpEntryPoint) 4235f757f3fSDimitry Andric .addImm(static_cast<uint32_t>(executionModel)) 42481ad6265SDimitry Andric .addUse(FuncVReg); 42581ad6265SDimitry Andric addStringImm(F.getName(), MIB); 426*0fca6ea1SDimitry Andric } else if (F.getLinkage() != GlobalValue::InternalLinkage && 427*0fca6ea1SDimitry Andric F.getLinkage() != GlobalValue::PrivateLinkage) { 428*0fca6ea1SDimitry Andric SPIRV::LinkageType::LinkageType LnkTy = 429*0fca6ea1SDimitry Andric F.isDeclaration() 430*0fca6ea1SDimitry Andric ? SPIRV::LinkageType::Import 431*0fca6ea1SDimitry Andric : (F.getLinkage() == GlobalValue::LinkOnceODRLinkage && 432*0fca6ea1SDimitry Andric ST->canUseExtension( 433*0fca6ea1SDimitry Andric SPIRV::Extension::SPV_KHR_linkonce_odr) 434*0fca6ea1SDimitry Andric ? SPIRV::LinkageType::LinkOnceODR 435*0fca6ea1SDimitry Andric : SPIRV::LinkageType::Export); 43681ad6265SDimitry Andric buildOpDecorate(FuncVReg, MIRBuilder, SPIRV::Decoration::LinkageAttributes, 43781ad6265SDimitry Andric {static_cast<uint32_t>(LnkTy)}, F.getGlobalIdentifier()); 43881ad6265SDimitry Andric } 43981ad6265SDimitry Andric 440*0fca6ea1SDimitry Andric // Handle function pointers decoration 441*0fca6ea1SDimitry Andric bool hasFunctionPointers = 442*0fca6ea1SDimitry Andric ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers); 443*0fca6ea1SDimitry Andric if (hasFunctionPointers) { 444*0fca6ea1SDimitry Andric if (F.hasFnAttribute("referenced-indirectly")) { 445*0fca6ea1SDimitry Andric assert((F.getCallingConv() != CallingConv::SPIR_KERNEL) && 446*0fca6ea1SDimitry Andric "Unexpected 'referenced-indirectly' attribute of the kernel " 447*0fca6ea1SDimitry Andric "function"); 448*0fca6ea1SDimitry Andric buildOpDecorate(FuncVReg, MIRBuilder, 449*0fca6ea1SDimitry Andric SPIRV::Decoration::ReferencedIndirectlyINTEL, {}); 450*0fca6ea1SDimitry Andric } 451*0fca6ea1SDimitry Andric } 452*0fca6ea1SDimitry Andric 45381ad6265SDimitry Andric return true; 45481ad6265SDimitry Andric } 45581ad6265SDimitry Andric 456*0fca6ea1SDimitry Andric // Used to postpone producing of indirect function pointer types after all 457*0fca6ea1SDimitry Andric // indirect calls info is collected 458*0fca6ea1SDimitry Andric // TODO: 459*0fca6ea1SDimitry Andric // - add a topological sort of IndirectCalls to ensure the best types knowledge 460*0fca6ea1SDimitry Andric // - we may need to fix function formal parameter types if they are opaque 461*0fca6ea1SDimitry Andric // pointers used as function pointers in these indirect calls 462*0fca6ea1SDimitry Andric void SPIRVCallLowering::produceIndirectPtrTypes( 463*0fca6ea1SDimitry Andric MachineIRBuilder &MIRBuilder) const { 464*0fca6ea1SDimitry Andric // Create indirect call data types if any 465*0fca6ea1SDimitry Andric MachineFunction &MF = MIRBuilder.getMF(); 466*0fca6ea1SDimitry Andric for (auto const &IC : IndirectCalls) { 467*0fca6ea1SDimitry Andric SPIRVType *SpirvRetTy = GR->getOrCreateSPIRVType(IC.RetTy, MIRBuilder); 468*0fca6ea1SDimitry Andric SmallVector<SPIRVType *, 4> SpirvArgTypes; 469*0fca6ea1SDimitry Andric for (size_t i = 0; i < IC.ArgTys.size(); ++i) { 470*0fca6ea1SDimitry Andric SPIRVType *SPIRVTy = GR->getOrCreateSPIRVType(IC.ArgTys[i], MIRBuilder); 471*0fca6ea1SDimitry Andric SpirvArgTypes.push_back(SPIRVTy); 472*0fca6ea1SDimitry Andric if (!GR->getSPIRVTypeForVReg(IC.ArgRegs[i])) 473*0fca6ea1SDimitry Andric GR->assignSPIRVTypeToVReg(SPIRVTy, IC.ArgRegs[i], MF); 474*0fca6ea1SDimitry Andric } 475*0fca6ea1SDimitry Andric // SPIR-V function type: 476*0fca6ea1SDimitry Andric FunctionType *FTy = 477*0fca6ea1SDimitry Andric FunctionType::get(const_cast<Type *>(IC.RetTy), IC.ArgTys, false); 478*0fca6ea1SDimitry Andric SPIRVType *SpirvFuncTy = GR->getOrCreateOpTypeFunctionWithArgs( 479*0fca6ea1SDimitry Andric FTy, SpirvRetTy, SpirvArgTypes, MIRBuilder); 480*0fca6ea1SDimitry Andric // SPIR-V pointer to function type: 481*0fca6ea1SDimitry Andric SPIRVType *IndirectFuncPtrTy = GR->getOrCreateSPIRVPointerType( 482*0fca6ea1SDimitry Andric SpirvFuncTy, MIRBuilder, SPIRV::StorageClass::Function); 483*0fca6ea1SDimitry Andric // Correct the Callee type 484*0fca6ea1SDimitry Andric GR->assignSPIRVTypeToVReg(IndirectFuncPtrTy, IC.Callee, MF); 485*0fca6ea1SDimitry Andric } 486*0fca6ea1SDimitry Andric } 487*0fca6ea1SDimitry Andric 48881ad6265SDimitry Andric bool SPIRVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, 48981ad6265SDimitry Andric CallLoweringInfo &Info) const { 49081ad6265SDimitry Andric // Currently call returns should have single vregs. 49181ad6265SDimitry Andric // TODO: handle the case of multiple registers. 49281ad6265SDimitry Andric if (Info.OrigRet.Regs.size() > 1) 49381ad6265SDimitry Andric return false; 494fcaf7f86SDimitry Andric MachineFunction &MF = MIRBuilder.getMF(); 495fcaf7f86SDimitry Andric GR->setCurrentFunc(MF); 496fcaf7f86SDimitry Andric const Function *CF = nullptr; 497*0fca6ea1SDimitry Andric std::string DemangledName; 498*0fca6ea1SDimitry Andric const Type *OrigRetTy = Info.OrigRet.Ty; 49981ad6265SDimitry Andric 50081ad6265SDimitry Andric // Emit a regular OpFunctionCall. If it's an externally declared function, 501fcaf7f86SDimitry Andric // be sure to emit its type and function declaration here. It will be hoisted 502fcaf7f86SDimitry Andric // globally later. 50381ad6265SDimitry Andric if (Info.Callee.isGlobal()) { 504*0fca6ea1SDimitry Andric std::string FuncName = Info.Callee.getGlobal()->getName().str(); 505*0fca6ea1SDimitry Andric DemangledName = getOclOrSpirvBuiltinDemangledName(FuncName); 506fcaf7f86SDimitry Andric CF = dyn_cast_or_null<const Function>(Info.Callee.getGlobal()); 50781ad6265SDimitry Andric // TODO: support constexpr casts and indirect calls. 50881ad6265SDimitry Andric if (CF == nullptr) 50981ad6265SDimitry Andric return false; 510*0fca6ea1SDimitry Andric if (FunctionType *FTy = getOriginalFunctionType(*CF)) { 511*0fca6ea1SDimitry Andric OrigRetTy = FTy->getReturnType(); 512*0fca6ea1SDimitry Andric if (isUntypedPointerTy(OrigRetTy)) { 513*0fca6ea1SDimitry Andric if (auto *DerivedRetTy = GR->findReturnType(CF)) 514*0fca6ea1SDimitry Andric OrigRetTy = DerivedRetTy; 515*0fca6ea1SDimitry Andric } 516*0fca6ea1SDimitry Andric } 517fcaf7f86SDimitry Andric } 518fcaf7f86SDimitry Andric 51906c3fb27SDimitry Andric MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 520fcaf7f86SDimitry Andric Register ResVReg = 521fcaf7f86SDimitry Andric Info.OrigRet.Regs.empty() ? Register(0) : Info.OrigRet.Regs[0]; 522bdd1243dSDimitry Andric const auto *ST = static_cast<const SPIRVSubtarget *>(&MF.getSubtarget()); 523*0fca6ea1SDimitry Andric 524*0fca6ea1SDimitry Andric bool isFunctionDecl = CF && CF->isDeclaration(); 525*0fca6ea1SDimitry Andric bool canUseOpenCL = ST->canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std); 526*0fca6ea1SDimitry Andric bool canUseGLSL = ST->canUseExtInstSet(SPIRV::InstructionSet::GLSL_std_450); 527*0fca6ea1SDimitry Andric assert(canUseGLSL != canUseOpenCL && 528*0fca6ea1SDimitry Andric "Scenario where both sets are enabled is not supported."); 529*0fca6ea1SDimitry Andric 530*0fca6ea1SDimitry Andric if (isFunctionDecl && !DemangledName.empty() && 531*0fca6ea1SDimitry Andric (canUseGLSL || canUseOpenCL)) { 532bdd1243dSDimitry Andric SmallVector<Register, 8> ArgVRegs; 533bdd1243dSDimitry Andric for (auto Arg : Info.OrigArgs) { 534bdd1243dSDimitry Andric assert(Arg.Regs.size() == 1 && "Call arg has multiple VRegs"); 535bdd1243dSDimitry Andric ArgVRegs.push_back(Arg.Regs[0]); 536bdd1243dSDimitry Andric SPIRVType *SPIRVTy = GR->getOrCreateSPIRVType(Arg.Ty, MIRBuilder); 5371db9f3b2SDimitry Andric if (!GR->getSPIRVTypeForVReg(Arg.Regs[0])) 538*0fca6ea1SDimitry Andric GR->assignSPIRVTypeToVReg(SPIRVTy, Arg.Regs[0], MF); 539bdd1243dSDimitry Andric } 540*0fca6ea1SDimitry Andric auto instructionSet = canUseOpenCL ? SPIRV::InstructionSet::OpenCL_std 541*0fca6ea1SDimitry Andric : SPIRV::InstructionSet::GLSL_std_450; 542*0fca6ea1SDimitry Andric if (auto Res = 543*0fca6ea1SDimitry Andric SPIRV::lowerBuiltin(DemangledName, instructionSet, MIRBuilder, 544bdd1243dSDimitry Andric ResVReg, OrigRetTy, ArgVRegs, GR)) 545bdd1243dSDimitry Andric return *Res; 546bdd1243dSDimitry Andric } 547*0fca6ea1SDimitry Andric 548*0fca6ea1SDimitry Andric if (isFunctionDecl && !GR->find(CF, &MF).isValid()) { 54981ad6265SDimitry Andric // Emit the type info and forward function declaration to the first MBB 55081ad6265SDimitry Andric // to ensure VReg definition dependencies are valid across all MBBs. 551fcaf7f86SDimitry Andric MachineIRBuilder FirstBlockBuilder; 552fcaf7f86SDimitry Andric FirstBlockBuilder.setMF(MF); 553fcaf7f86SDimitry Andric FirstBlockBuilder.setMBB(*MF.getBlockNumbered(0)); 55481ad6265SDimitry Andric 55581ad6265SDimitry Andric SmallVector<ArrayRef<Register>, 8> VRegArgs; 55681ad6265SDimitry Andric SmallVector<SmallVector<Register, 1>, 8> ToInsert; 55781ad6265SDimitry Andric for (const Argument &Arg : CF->args()) { 55881ad6265SDimitry Andric if (MIRBuilder.getDataLayout().getTypeStoreSize(Arg.getType()).isZero()) 55981ad6265SDimitry Andric continue; // Don't handle zero sized types. 56006c3fb27SDimitry Andric Register Reg = MRI->createGenericVirtualRegister(LLT::scalar(32)); 56106c3fb27SDimitry Andric MRI->setRegClass(Reg, &SPIRV::IDRegClass); 56206c3fb27SDimitry Andric ToInsert.push_back({Reg}); 56381ad6265SDimitry Andric VRegArgs.push_back(ToInsert.back()); 56481ad6265SDimitry Andric } 565fcaf7f86SDimitry Andric // TODO: Reuse FunctionLoweringInfo 56681ad6265SDimitry Andric FunctionLoweringInfo FuncInfo; 567fcaf7f86SDimitry Andric lowerFormalArguments(FirstBlockBuilder, *CF, VRegArgs, FuncInfo); 56881ad6265SDimitry Andric } 56981ad6265SDimitry Andric 570*0fca6ea1SDimitry Andric unsigned CallOp; 571*0fca6ea1SDimitry Andric if (Info.CB->isIndirectCall()) { 572*0fca6ea1SDimitry Andric if (!ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) 573*0fca6ea1SDimitry Andric report_fatal_error("An indirect call is encountered but SPIR-V without " 574*0fca6ea1SDimitry Andric "extensions does not support it", 575*0fca6ea1SDimitry Andric false); 576*0fca6ea1SDimitry Andric // Set instruction operation according to SPV_INTEL_function_pointers 577*0fca6ea1SDimitry Andric CallOp = SPIRV::OpFunctionPointerCallINTEL; 578*0fca6ea1SDimitry Andric // Collect information about the indirect call to support possible 579*0fca6ea1SDimitry Andric // specification of opaque ptr types of parent function's parameters 580*0fca6ea1SDimitry Andric Register CalleeReg = Info.Callee.getReg(); 581*0fca6ea1SDimitry Andric if (CalleeReg.isValid()) { 582*0fca6ea1SDimitry Andric SPIRVCallLowering::SPIRVIndirectCall IndirectCall; 583*0fca6ea1SDimitry Andric IndirectCall.Callee = CalleeReg; 584*0fca6ea1SDimitry Andric IndirectCall.RetTy = OrigRetTy; 585*0fca6ea1SDimitry Andric for (const auto &Arg : Info.OrigArgs) { 586*0fca6ea1SDimitry Andric assert(Arg.Regs.size() == 1 && "Call arg has multiple VRegs"); 587*0fca6ea1SDimitry Andric IndirectCall.ArgTys.push_back(Arg.Ty); 588*0fca6ea1SDimitry Andric IndirectCall.ArgRegs.push_back(Arg.Regs[0]); 589*0fca6ea1SDimitry Andric } 590*0fca6ea1SDimitry Andric IndirectCalls.push_back(IndirectCall); 591*0fca6ea1SDimitry Andric } 592*0fca6ea1SDimitry Andric } else { 593*0fca6ea1SDimitry Andric // Emit a regular OpFunctionCall 594*0fca6ea1SDimitry Andric CallOp = SPIRV::OpFunctionCall; 595*0fca6ea1SDimitry Andric } 596*0fca6ea1SDimitry Andric 59781ad6265SDimitry Andric // Make sure there's a valid return reg, even for functions returning void. 598fcaf7f86SDimitry Andric if (!ResVReg.isValid()) 59981ad6265SDimitry Andric ResVReg = MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::IDRegClass); 600*0fca6ea1SDimitry Andric SPIRVType *RetType = GR->assignTypeToVReg(OrigRetTy, ResVReg, MIRBuilder); 60181ad6265SDimitry Andric 602*0fca6ea1SDimitry Andric // Emit the call instruction and its args. 603*0fca6ea1SDimitry Andric auto MIB = MIRBuilder.buildInstr(CallOp) 60481ad6265SDimitry Andric .addDef(ResVReg) 60581ad6265SDimitry Andric .addUse(GR->getSPIRVTypeID(RetType)) 60681ad6265SDimitry Andric .add(Info.Callee); 60781ad6265SDimitry Andric 60881ad6265SDimitry Andric for (const auto &Arg : Info.OrigArgs) { 60981ad6265SDimitry Andric // Currently call args should have single vregs. 61081ad6265SDimitry Andric if (Arg.Regs.size() > 1) 61181ad6265SDimitry Andric return false; 61281ad6265SDimitry Andric MIB.addUse(Arg.Regs[0]); 61381ad6265SDimitry Andric } 614bdd1243dSDimitry Andric return MIB.constrainAllUses(MIRBuilder.getTII(), *ST->getRegisterInfo(), 615bdd1243dSDimitry Andric *ST->getRegBankInfo()); 61681ad6265SDimitry Andric } 617