1ec259036SIlia Diachkov //===--- SPIRVCallLowering.cpp - Call lowering ------------------*- C++ -*-===// 2ec259036SIlia Diachkov // 3ec259036SIlia Diachkov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4ec259036SIlia Diachkov // See https://llvm.org/LICENSE.txt for license information. 5ec259036SIlia Diachkov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ec259036SIlia Diachkov // 7ec259036SIlia Diachkov //===----------------------------------------------------------------------===// 8ec259036SIlia Diachkov // 9ec259036SIlia Diachkov // This file implements the lowering of LLVM calls to machine code calls for 10ec259036SIlia Diachkov // GlobalISel. 11ec259036SIlia Diachkov // 12ec259036SIlia Diachkov //===----------------------------------------------------------------------===// 13ec259036SIlia Diachkov 14ec259036SIlia Diachkov #include "SPIRVCallLowering.h" 15eab7d363SIlia Diachkov #include "MCTargetDesc/SPIRVBaseInfo.h" 16ec259036SIlia Diachkov #include "SPIRV.h" 17f61eb416SIlia Diachkov #include "SPIRVBuiltins.h" 18eab7d363SIlia Diachkov #include "SPIRVGlobalRegistry.h" 19ec259036SIlia Diachkov #include "SPIRVISelLowering.h" 200fbaf03fSMichal Paszkowski #include "SPIRVMetadata.h" 21ec259036SIlia Diachkov #include "SPIRVRegisterInfo.h" 22ec259036SIlia Diachkov #include "SPIRVSubtarget.h" 23eab7d363SIlia Diachkov #include "SPIRVUtils.h" 24ec259036SIlia Diachkov #include "llvm/CodeGen/FunctionLoweringInfo.h" 2543222bd3SMichal Paszkowski #include "llvm/IR/IntrinsicInst.h" 2643222bd3SMichal Paszkowski #include "llvm/IR/IntrinsicsSPIRV.h" 27b0020f42SMichal Paszkowski #include "llvm/Support/ModRef.h" 28ec259036SIlia Diachkov 29ec259036SIlia Diachkov using namespace llvm; 30ec259036SIlia Diachkov 31eab7d363SIlia Diachkov SPIRVCallLowering::SPIRVCallLowering(const SPIRVTargetLowering &TLI, 32eab7d363SIlia Diachkov SPIRVGlobalRegistry *GR) 33b8e1544bSIlia Diachkov : CallLowering(&TLI), GR(GR) {} 34ec259036SIlia Diachkov 35ec259036SIlia Diachkov bool SPIRVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder, 36ec259036SIlia Diachkov const Value *Val, ArrayRef<Register> VRegs, 37ec259036SIlia Diachkov FunctionLoweringInfo &FLI, 38ec259036SIlia Diachkov Register SwiftErrorVReg) const { 398d8996ddSVyacheslav Levytskyy // Ignore if called from the internal service function 408d8996ddSVyacheslav Levytskyy if (MIRBuilder.getMF() 418d8996ddSVyacheslav Levytskyy .getFunction() 428d8996ddSVyacheslav Levytskyy .getFnAttribute(SPIRV_BACKEND_SERVICE_FUN_NAME) 438d8996ddSVyacheslav Levytskyy .isValid()) 448d8996ddSVyacheslav Levytskyy return true; 458d8996ddSVyacheslav Levytskyy 46d153ef6aSVyacheslav Levytskyy // Maybe run postponed production of types for function pointers 47d153ef6aSVyacheslav Levytskyy if (IndirectCalls.size() > 0) { 48d153ef6aSVyacheslav Levytskyy produceIndirectPtrTypes(MIRBuilder); 49d153ef6aSVyacheslav Levytskyy IndirectCalls.clear(); 50d153ef6aSVyacheslav Levytskyy } 51d153ef6aSVyacheslav Levytskyy 52ec259036SIlia Diachkov // Currently all return types should use a single register. 53ec259036SIlia Diachkov // TODO: handle the case of multiple registers. 54ec259036SIlia Diachkov if (VRegs.size() > 1) 55ec259036SIlia Diachkov return false; 56b8e1544bSIlia Diachkov if (Val) { 57b8e1544bSIlia Diachkov const auto &STI = MIRBuilder.getMF().getSubtarget(); 58eab7d363SIlia Diachkov return MIRBuilder.buildInstr(SPIRV::OpReturnValue) 59eab7d363SIlia Diachkov .addUse(VRegs[0]) 60b8e1544bSIlia Diachkov .constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(), 61b8e1544bSIlia Diachkov *STI.getRegBankInfo()); 62b8e1544bSIlia Diachkov } 63ec259036SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpReturn); 64ec259036SIlia Diachkov return true; 65ec259036SIlia Diachkov } 66ec259036SIlia Diachkov 67eab7d363SIlia Diachkov // Based on the LLVM function attributes, get a SPIR-V FunctionControl. 68874b4fb6SVyacheslav Levytskyy static uint32_t getFunctionControl(const Function &F, 69874b4fb6SVyacheslav Levytskyy const SPIRVSubtarget *ST) { 70b0020f42SMichal Paszkowski MemoryEffects MemEffects = F.getMemoryEffects(); 71b0020f42SMichal Paszkowski 72eab7d363SIlia Diachkov uint32_t FuncControl = static_cast<uint32_t>(SPIRV::FunctionControl::None); 73b0020f42SMichal Paszkowski 74b0020f42SMichal Paszkowski if (F.hasFnAttribute(Attribute::AttrKind::NoInline)) 75eab7d363SIlia Diachkov FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::DontInline); 76b0020f42SMichal Paszkowski else if (F.hasFnAttribute(Attribute::AttrKind::AlwaysInline)) 77b0020f42SMichal Paszkowski FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Inline); 78b0020f42SMichal Paszkowski 79b0020f42SMichal Paszkowski if (MemEffects.doesNotAccessMemory()) 80b0020f42SMichal Paszkowski FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Pure); 81b0020f42SMichal Paszkowski else if (MemEffects.onlyReadsMemory()) 82b0020f42SMichal Paszkowski FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::Const); 83b0020f42SMichal Paszkowski 84874b4fb6SVyacheslav Levytskyy if (ST->canUseExtension(SPIRV::Extension::SPV_INTEL_optnone) || 85874b4fb6SVyacheslav Levytskyy ST->canUseExtension(SPIRV::Extension::SPV_EXT_optnone)) 86874b4fb6SVyacheslav Levytskyy if (F.hasFnAttribute(Attribute::OptimizeNone)) 87874b4fb6SVyacheslav Levytskyy FuncControl |= static_cast<uint32_t>(SPIRV::FunctionControl::OptNoneEXT); 88874b4fb6SVyacheslav Levytskyy 89eab7d363SIlia Diachkov return FuncControl; 90eab7d363SIlia Diachkov } 91eab7d363SIlia Diachkov 92b8e1544bSIlia Diachkov static ConstantInt *getConstInt(MDNode *MD, unsigned NumOp) { 93b8e1544bSIlia Diachkov if (MD->getNumOperands() > NumOp) { 94b8e1544bSIlia Diachkov auto *CMeta = dyn_cast<ConstantAsMetadata>(MD->getOperand(NumOp)); 95b8e1544bSIlia Diachkov if (CMeta) 96b8e1544bSIlia Diachkov return dyn_cast<ConstantInt>(CMeta->getValue()); 97b8e1544bSIlia Diachkov } 98b8e1544bSIlia Diachkov return nullptr; 99b8e1544bSIlia Diachkov } 100b8e1544bSIlia Diachkov 1010a443f13SVyacheslav Levytskyy // If the function has pointer arguments, we are forced to re-create this 1020a443f13SVyacheslav Levytskyy // function type from the very beginning, changing PointerType by 1030a443f13SVyacheslav Levytskyy // TypedPointerType for each pointer argument. Otherwise, the same `Type*` 1040a443f13SVyacheslav Levytskyy // potentially corresponds to different SPIR-V function type, effectively 1050a443f13SVyacheslav Levytskyy // invalidating logic behind global registry and duplicates tracker. 1060a443f13SVyacheslav Levytskyy static FunctionType * 1070a443f13SVyacheslav Levytskyy fixFunctionTypeIfPtrArgs(SPIRVGlobalRegistry *GR, const Function &F, 1080a443f13SVyacheslav Levytskyy FunctionType *FTy, const SPIRVType *SRetTy, 1090a443f13SVyacheslav Levytskyy const SmallVector<SPIRVType *, 4> &SArgTys) { 1100a443f13SVyacheslav Levytskyy bool hasArgPtrs = false; 1110a443f13SVyacheslav Levytskyy for (auto &Arg : F.args()) { 1120a443f13SVyacheslav Levytskyy // check if it's an instance of a non-typed PointerType 1130a443f13SVyacheslav Levytskyy if (Arg.getType()->isPointerTy()) { 1140a443f13SVyacheslav Levytskyy hasArgPtrs = true; 1150a443f13SVyacheslav Levytskyy break; 1160a443f13SVyacheslav Levytskyy } 1170a443f13SVyacheslav Levytskyy } 1180a443f13SVyacheslav Levytskyy if (!hasArgPtrs) { 1190a443f13SVyacheslav Levytskyy Type *RetTy = FTy->getReturnType(); 1200a443f13SVyacheslav Levytskyy // check if it's an instance of a non-typed PointerType 1210a443f13SVyacheslav Levytskyy if (!RetTy->isPointerTy()) 1220a443f13SVyacheslav Levytskyy return FTy; 1230a443f13SVyacheslav Levytskyy } 1240a443f13SVyacheslav Levytskyy 1250a443f13SVyacheslav Levytskyy // re-create function type, using TypedPointerType instead of PointerType to 1260a443f13SVyacheslav Levytskyy // properly trace argument types 1270a443f13SVyacheslav Levytskyy const Type *RetTy = GR->getTypeForSPIRVType(SRetTy); 1280a443f13SVyacheslav Levytskyy SmallVector<Type *, 4> ArgTys; 1290a443f13SVyacheslav Levytskyy for (auto SArgTy : SArgTys) 1300a443f13SVyacheslav Levytskyy ArgTys.push_back(const_cast<Type *>(GR->getTypeForSPIRVType(SArgTy))); 1310a443f13SVyacheslav Levytskyy return FunctionType::get(const_cast<Type *>(RetTy), ArgTys, false); 1320a443f13SVyacheslav Levytskyy } 1330a443f13SVyacheslav Levytskyy 134b8e1544bSIlia Diachkov // This code restores function args/retvalue types for composite cases 135b8e1544bSIlia Diachkov // because the final types should still be aggregate whereas they're i32 136b8e1544bSIlia Diachkov // during the translation to cope with aggregate flattening etc. 137b8e1544bSIlia Diachkov static FunctionType *getOriginalFunctionType(const Function &F) { 138b8e1544bSIlia Diachkov auto *NamedMD = F.getParent()->getNamedMetadata("spv.cloned_funcs"); 139b8e1544bSIlia Diachkov if (NamedMD == nullptr) 140b8e1544bSIlia Diachkov return F.getFunctionType(); 141b8e1544bSIlia Diachkov 142b8e1544bSIlia Diachkov Type *RetTy = F.getFunctionType()->getReturnType(); 143b8e1544bSIlia Diachkov SmallVector<Type *, 4> ArgTypes; 144b8e1544bSIlia Diachkov for (auto &Arg : F.args()) 145b8e1544bSIlia Diachkov ArgTypes.push_back(Arg.getType()); 146b8e1544bSIlia Diachkov 147b8e1544bSIlia Diachkov auto ThisFuncMDIt = 148b8e1544bSIlia Diachkov std::find_if(NamedMD->op_begin(), NamedMD->op_end(), [&F](MDNode *N) { 149b8e1544bSIlia Diachkov return isa<MDString>(N->getOperand(0)) && 150b8e1544bSIlia Diachkov cast<MDString>(N->getOperand(0))->getString() == F.getName(); 151b8e1544bSIlia Diachkov }); 152b8e1544bSIlia Diachkov // TODO: probably one function can have numerous type mutations, 153b8e1544bSIlia Diachkov // so we should support this. 154b8e1544bSIlia Diachkov if (ThisFuncMDIt != NamedMD->op_end()) { 155b8e1544bSIlia Diachkov auto *ThisFuncMD = *ThisFuncMDIt; 156b8e1544bSIlia Diachkov MDNode *MD = dyn_cast<MDNode>(ThisFuncMD->getOperand(1)); 157b8e1544bSIlia Diachkov assert(MD && "MDNode operand is expected"); 158b8e1544bSIlia Diachkov ConstantInt *Const = getConstInt(MD, 0); 159b8e1544bSIlia Diachkov if (Const) { 160b8e1544bSIlia Diachkov auto *CMeta = dyn_cast<ConstantAsMetadata>(MD->getOperand(1)); 161b8e1544bSIlia Diachkov assert(CMeta && "ConstantAsMetadata operand is expected"); 162b8e1544bSIlia Diachkov assert(Const->getSExtValue() >= -1); 163b8e1544bSIlia Diachkov // Currently -1 indicates return value, greater values mean 164b8e1544bSIlia Diachkov // argument numbers. 165b8e1544bSIlia Diachkov if (Const->getSExtValue() == -1) 166b8e1544bSIlia Diachkov RetTy = CMeta->getType(); 167b8e1544bSIlia Diachkov else 168b8e1544bSIlia Diachkov ArgTypes[Const->getSExtValue()] = CMeta->getType(); 169b8e1544bSIlia Diachkov } 170b8e1544bSIlia Diachkov } 171b8e1544bSIlia Diachkov 172b8e1544bSIlia Diachkov return FunctionType::get(RetTy, ArgTypes, F.isVarArg()); 173b8e1544bSIlia Diachkov } 174b8e1544bSIlia Diachkov 17525ee36c6SIlia Diachkov static SPIRV::AccessQualifier::AccessQualifier 17625ee36c6SIlia Diachkov getArgAccessQual(const Function &F, unsigned ArgIdx) { 17725ee36c6SIlia Diachkov if (F.getCallingConv() != CallingConv::SPIR_KERNEL) 17825ee36c6SIlia Diachkov return SPIRV::AccessQualifier::ReadWrite; 17925ee36c6SIlia Diachkov 1800fbaf03fSMichal Paszkowski MDString *ArgAttribute = getOCLKernelArgAccessQual(F, ArgIdx); 18125ee36c6SIlia Diachkov if (!ArgAttribute) 18225ee36c6SIlia Diachkov return SPIRV::AccessQualifier::ReadWrite; 18325ee36c6SIlia Diachkov 184b603237bSKazu Hirata if (ArgAttribute->getString() == "read_only") 18525ee36c6SIlia Diachkov return SPIRV::AccessQualifier::ReadOnly; 186b603237bSKazu Hirata if (ArgAttribute->getString() == "write_only") 18725ee36c6SIlia Diachkov return SPIRV::AccessQualifier::WriteOnly; 18825ee36c6SIlia Diachkov return SPIRV::AccessQualifier::ReadWrite; 18925ee36c6SIlia Diachkov } 19025ee36c6SIlia Diachkov 19125ee36c6SIlia Diachkov static std::vector<SPIRV::Decoration::Decoration> 1920fbaf03fSMichal Paszkowski getKernelArgTypeQual(const Function &F, unsigned ArgIdx) { 1930fbaf03fSMichal Paszkowski MDString *ArgAttribute = getOCLKernelArgTypeQual(F, ArgIdx); 194b603237bSKazu Hirata if (ArgAttribute && ArgAttribute->getString() == "volatile") 19525ee36c6SIlia Diachkov return {SPIRV::Decoration::Volatile}; 19625ee36c6SIlia Diachkov return {}; 19725ee36c6SIlia Diachkov } 19825ee36c6SIlia Diachkov 19981751905SMichal Paszkowski static SPIRVType *getArgSPIRVType(const Function &F, unsigned ArgIdx, 20081751905SMichal Paszkowski SPIRVGlobalRegistry *GR, 2014a602d92SVyacheslav Levytskyy MachineIRBuilder &MIRBuilder, 2024a602d92SVyacheslav Levytskyy const SPIRVSubtarget &ST) { 20381751905SMichal Paszkowski // Read argument's access qualifier from metadata or default. 20481751905SMichal Paszkowski SPIRV::AccessQualifier::AccessQualifier ArgAccessQual = 20581751905SMichal Paszkowski getArgAccessQual(F, ArgIdx); 20681751905SMichal Paszkowski 20725ee36c6SIlia Diachkov Type *OriginalArgType = getOriginalFunctionType(F)->getParamType(ArgIdx); 20881751905SMichal Paszkowski 20943222bd3SMichal Paszkowski // If OriginalArgType is non-pointer, use the OriginalArgType (the type cannot 21043222bd3SMichal Paszkowski // be legally reassigned later). 2110a443f13SVyacheslav Levytskyy if (!isPointerTy(OriginalArgType)) 21281751905SMichal Paszkowski return GR->getOrCreateSPIRVType(OriginalArgType, MIRBuilder, ArgAccessQual); 21325ee36c6SIlia Diachkov 214b7ac8fddSVyacheslav Levytskyy Argument *Arg = F.getArg(ArgIdx); 215b7ac8fddSVyacheslav Levytskyy Type *ArgType = Arg->getType(); 216b7ac8fddSVyacheslav Levytskyy if (isTypedPointerTy(ArgType)) { 217b7ac8fddSVyacheslav Levytskyy SPIRVType *ElementType = GR->getOrCreateSPIRVType( 218b7ac8fddSVyacheslav Levytskyy cast<TypedPointerType>(ArgType)->getElementType(), MIRBuilder); 219b7ac8fddSVyacheslav Levytskyy return GR->getOrCreateSPIRVPointerType( 220b7ac8fddSVyacheslav Levytskyy ElementType, MIRBuilder, 221b7ac8fddSVyacheslav Levytskyy addressSpaceToStorageClass(getPointerAddressSpace(ArgType), ST)); 222b7ac8fddSVyacheslav Levytskyy } 223b7ac8fddSVyacheslav Levytskyy 224b7ac8fddSVyacheslav Levytskyy // In case OriginalArgType is of untyped pointer type, there are three 225b7ac8fddSVyacheslav Levytskyy // possibilities: 22643222bd3SMichal Paszkowski // 1) This is a pointer of an LLVM IR element type, passed byval/byref. 22743222bd3SMichal Paszkowski // 2) This is an OpenCL/SPIR-V builtin type if there is spv_assign_type 22843222bd3SMichal Paszkowski // intrinsic assigning a TargetExtType. 22943222bd3SMichal Paszkowski // 3) This is a pointer, try to retrieve pointer element type from a 23043222bd3SMichal Paszkowski // spv_assign_ptr_type intrinsic or otherwise use default pointer element 23143222bd3SMichal Paszkowski // type. 232b7ac8fddSVyacheslav Levytskyy if (hasPointeeTypeAttr(Arg)) { 233b7ac8fddSVyacheslav Levytskyy SPIRVType *ElementType = 234b7ac8fddSVyacheslav Levytskyy GR->getOrCreateSPIRVType(getPointeeTypeByAttr(Arg), MIRBuilder); 23543222bd3SMichal Paszkowski return GR->getOrCreateSPIRVPointerType( 23643222bd3SMichal Paszkowski ElementType, MIRBuilder, 237b7ac8fddSVyacheslav Levytskyy addressSpaceToStorageClass(getPointerAddressSpace(ArgType), ST)); 2385a07774fSVyacheslav Levytskyy } 23943222bd3SMichal Paszkowski 24043222bd3SMichal Paszkowski for (auto User : Arg->users()) { 24143222bd3SMichal Paszkowski auto *II = dyn_cast<IntrinsicInst>(User); 24243222bd3SMichal Paszkowski // Check if this is spv_assign_type assigning OpenCL/SPIR-V builtin type. 24343222bd3SMichal Paszkowski if (II && II->getIntrinsicID() == Intrinsic::spv_assign_type) { 24443222bd3SMichal Paszkowski MetadataAsValue *VMD = cast<MetadataAsValue>(II->getOperand(1)); 24543222bd3SMichal Paszkowski Type *BuiltinType = 24643222bd3SMichal Paszkowski cast<ConstantAsMetadata>(VMD->getMetadata())->getType(); 24743222bd3SMichal Paszkowski assert(BuiltinType->isTargetExtTy() && "Expected TargetExtType"); 24843222bd3SMichal Paszkowski return GR->getOrCreateSPIRVType(BuiltinType, MIRBuilder, ArgAccessQual); 24943222bd3SMichal Paszkowski } 25043222bd3SMichal Paszkowski 25143222bd3SMichal Paszkowski // Check if this is spv_assign_ptr_type assigning pointer element type. 25243222bd3SMichal Paszkowski if (!II || II->getIntrinsicID() != Intrinsic::spv_assign_ptr_type) 25343222bd3SMichal Paszkowski continue; 25443222bd3SMichal Paszkowski 25543222bd3SMichal Paszkowski MetadataAsValue *VMD = cast<MetadataAsValue>(II->getOperand(1)); 2569a737109SVyacheslav Levytskyy Type *ElementTy = 2579a737109SVyacheslav Levytskyy toTypedPointer(cast<ConstantAsMetadata>(VMD->getMetadata())->getType()); 25847e996d8SVyacheslav Levytskyy SPIRVType *ElementType = GR->getOrCreateSPIRVType(ElementTy, MIRBuilder); 25943222bd3SMichal Paszkowski return GR->getOrCreateSPIRVPointerType( 26043222bd3SMichal Paszkowski ElementType, MIRBuilder, 26143222bd3SMichal Paszkowski addressSpaceToStorageClass( 26243222bd3SMichal Paszkowski cast<ConstantInt>(II->getOperand(2))->getZExtValue(), ST)); 26343222bd3SMichal Paszkowski } 26443222bd3SMichal Paszkowski 2656cce67a8SVyacheslav Levytskyy // Replace PointerType with TypedPointerType to be able to map SPIR-V types to 2666cce67a8SVyacheslav Levytskyy // LLVM types in a consistent manner 2679a737109SVyacheslav Levytskyy return GR->getOrCreateSPIRVType(toTypedPointer(OriginalArgType), MIRBuilder, 2689a737109SVyacheslav Levytskyy ArgAccessQual); 26925ee36c6SIlia Diachkov } 27025ee36c6SIlia Diachkov 27156396b25SNathan Gauër static SPIRV::ExecutionModel::ExecutionModel 27256396b25SNathan Gauër getExecutionModel(const SPIRVSubtarget &STI, const Function &F) { 27356396b25SNathan Gauër if (STI.isOpenCLEnv()) 27456396b25SNathan Gauër return SPIRV::ExecutionModel::Kernel; 27556396b25SNathan Gauër 27656396b25SNathan Gauër auto attribute = F.getFnAttribute("hlsl.shader"); 27756396b25SNathan Gauër if (!attribute.isValid()) { 27856396b25SNathan Gauër report_fatal_error( 27956396b25SNathan Gauër "This entry point lacks mandatory hlsl.shader attribute."); 28056396b25SNathan Gauër } 28156396b25SNathan Gauër 28256396b25SNathan Gauër const auto value = attribute.getValueAsString(); 28356396b25SNathan Gauër if (value == "compute") 28456396b25SNathan Gauër return SPIRV::ExecutionModel::GLCompute; 28556396b25SNathan Gauër 28656396b25SNathan Gauër report_fatal_error("This HLSL entry point is not supported by this backend."); 28756396b25SNathan Gauër } 28856396b25SNathan Gauër 289ec259036SIlia Diachkov bool SPIRVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder, 290ec259036SIlia Diachkov const Function &F, 291ec259036SIlia Diachkov ArrayRef<ArrayRef<Register>> VRegs, 292ec259036SIlia Diachkov FunctionLoweringInfo &FLI) const { 2938d8996ddSVyacheslav Levytskyy // Discard the internal service function 2948d8996ddSVyacheslav Levytskyy if (F.getFnAttribute(SPIRV_BACKEND_SERVICE_FUN_NAME).isValid()) 2958d8996ddSVyacheslav Levytskyy return true; 2968d8996ddSVyacheslav Levytskyy 297eab7d363SIlia Diachkov assert(GR && "Must initialize the SPIRV type registry before lowering args."); 298fa2a7a25SAleksandr Bezzubikov GR->setCurrentFunc(MIRBuilder.getMF()); 299eab7d363SIlia Diachkov 3004a602d92SVyacheslav Levytskyy // Get access to information about available extensions 3014a602d92SVyacheslav Levytskyy const SPIRVSubtarget *ST = 3024a602d92SVyacheslav Levytskyy static_cast<const SPIRVSubtarget *>(&MIRBuilder.getMF().getSubtarget()); 3034a602d92SVyacheslav Levytskyy 304ec259036SIlia Diachkov // Assign types and names to all args, and store their types for later. 305b8e1544bSIlia Diachkov SmallVector<SPIRVType *, 4> ArgTypeVRegs; 306ec259036SIlia Diachkov if (VRegs.size() > 0) { 307ec259036SIlia Diachkov unsigned i = 0; 308ec259036SIlia Diachkov for (const auto &Arg : F.args()) { 309ec259036SIlia Diachkov // Currently formal args should use single registers. 310ec259036SIlia Diachkov // TODO: handle the case of multiple registers. 311ec259036SIlia Diachkov if (VRegs[i].size() > 1) 312ec259036SIlia Diachkov return false; 3134a602d92SVyacheslav Levytskyy auto *SpirvTy = getArgSPIRVType(F, i, GR, MIRBuilder, *ST); 31481751905SMichal Paszkowski GR->assignSPIRVTypeToVReg(SpirvTy, VRegs[i][0], MIRBuilder.getMF()); 315b8e1544bSIlia Diachkov ArgTypeVRegs.push_back(SpirvTy); 316eab7d363SIlia Diachkov 317eab7d363SIlia Diachkov if (Arg.hasName()) 318eab7d363SIlia Diachkov buildOpName(VRegs[i][0], Arg.getName(), MIRBuilder); 319489db653SVyacheslav Levytskyy if (isPointerTyOrWrapper(Arg.getType())) { 320eab7d363SIlia Diachkov auto DerefBytes = static_cast<unsigned>(Arg.getDereferenceableBytes()); 321eab7d363SIlia Diachkov if (DerefBytes != 0) 322eab7d363SIlia Diachkov buildOpDecorate(VRegs[i][0], MIRBuilder, 323eab7d363SIlia Diachkov SPIRV::Decoration::MaxByteOffset, {DerefBytes}); 324eab7d363SIlia Diachkov } 325eab7d363SIlia Diachkov if (Arg.hasAttribute(Attribute::Alignment)) { 326b8e1544bSIlia Diachkov auto Alignment = static_cast<unsigned>( 327b8e1544bSIlia Diachkov Arg.getAttribute(Attribute::Alignment).getValueAsInt()); 328eab7d363SIlia Diachkov buildOpDecorate(VRegs[i][0], MIRBuilder, SPIRV::Decoration::Alignment, 329b8e1544bSIlia Diachkov {Alignment}); 330eab7d363SIlia Diachkov } 331eab7d363SIlia Diachkov if (Arg.hasAttribute(Attribute::ReadOnly)) { 332eab7d363SIlia Diachkov auto Attr = 333eab7d363SIlia Diachkov static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoWrite); 334eab7d363SIlia Diachkov buildOpDecorate(VRegs[i][0], MIRBuilder, 335eab7d363SIlia Diachkov SPIRV::Decoration::FuncParamAttr, {Attr}); 336eab7d363SIlia Diachkov } 337eab7d363SIlia Diachkov if (Arg.hasAttribute(Attribute::ZExt)) { 338eab7d363SIlia Diachkov auto Attr = 339eab7d363SIlia Diachkov static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Zext); 340eab7d363SIlia Diachkov buildOpDecorate(VRegs[i][0], MIRBuilder, 341eab7d363SIlia Diachkov SPIRV::Decoration::FuncParamAttr, {Attr}); 342eab7d363SIlia Diachkov } 343b8e1544bSIlia Diachkov if (Arg.hasAttribute(Attribute::NoAlias)) { 344b8e1544bSIlia Diachkov auto Attr = 345b8e1544bSIlia Diachkov static_cast<unsigned>(SPIRV::FunctionParameterAttribute::NoAlias); 346b8e1544bSIlia Diachkov buildOpDecorate(VRegs[i][0], MIRBuilder, 347b8e1544bSIlia Diachkov SPIRV::Decoration::FuncParamAttr, {Attr}); 348b8e1544bSIlia Diachkov } 349afec257dSVyacheslav Levytskyy if (Arg.hasAttribute(Attribute::ByVal)) { 350afec257dSVyacheslav Levytskyy auto Attr = 351afec257dSVyacheslav Levytskyy static_cast<unsigned>(SPIRV::FunctionParameterAttribute::ByVal); 352afec257dSVyacheslav Levytskyy buildOpDecorate(VRegs[i][0], MIRBuilder, 353afec257dSVyacheslav Levytskyy SPIRV::Decoration::FuncParamAttr, {Attr}); 354afec257dSVyacheslav Levytskyy } 355874b4fb6SVyacheslav Levytskyy if (Arg.hasAttribute(Attribute::StructRet)) { 356874b4fb6SVyacheslav Levytskyy auto Attr = 357874b4fb6SVyacheslav Levytskyy static_cast<unsigned>(SPIRV::FunctionParameterAttribute::Sret); 358874b4fb6SVyacheslav Levytskyy buildOpDecorate(VRegs[i][0], MIRBuilder, 359874b4fb6SVyacheslav Levytskyy SPIRV::Decoration::FuncParamAttr, {Attr}); 360874b4fb6SVyacheslav Levytskyy } 36125ee36c6SIlia Diachkov 36225ee36c6SIlia Diachkov if (F.getCallingConv() == CallingConv::SPIR_KERNEL) { 36325ee36c6SIlia Diachkov std::vector<SPIRV::Decoration::Decoration> ArgTypeQualDecs = 36425ee36c6SIlia Diachkov getKernelArgTypeQual(F, i); 36525ee36c6SIlia Diachkov for (SPIRV::Decoration::Decoration Decoration : ArgTypeQualDecs) 36625ee36c6SIlia Diachkov buildOpDecorate(VRegs[i][0], MIRBuilder, Decoration, {}); 367b8e1544bSIlia Diachkov } 36825ee36c6SIlia Diachkov 36925ee36c6SIlia Diachkov MDNode *Node = F.getMetadata("spirv.ParameterDecorations"); 370b8e1544bSIlia Diachkov if (Node && i < Node->getNumOperands() && 371b8e1544bSIlia Diachkov isa<MDNode>(Node->getOperand(i))) { 372b8e1544bSIlia Diachkov MDNode *MD = cast<MDNode>(Node->getOperand(i)); 373b8e1544bSIlia Diachkov for (const MDOperand &MDOp : MD->operands()) { 374b8e1544bSIlia Diachkov MDNode *MD2 = dyn_cast<MDNode>(MDOp); 375b8e1544bSIlia Diachkov assert(MD2 && "Metadata operand is expected"); 376b8e1544bSIlia Diachkov ConstantInt *Const = getConstInt(MD2, 0); 377b8e1544bSIlia Diachkov assert(Const && "MDOperand should be ConstantInt"); 378b25b507cSIlia Diachkov auto Dec = 379b25b507cSIlia Diachkov static_cast<SPIRV::Decoration::Decoration>(Const->getZExtValue()); 380b8e1544bSIlia Diachkov std::vector<uint32_t> DecVec; 381b8e1544bSIlia Diachkov for (unsigned j = 1; j < MD2->getNumOperands(); j++) { 382b8e1544bSIlia Diachkov ConstantInt *Const = getConstInt(MD2, j); 383b8e1544bSIlia Diachkov assert(Const && "MDOperand should be ConstantInt"); 384b8e1544bSIlia Diachkov DecVec.push_back(static_cast<uint32_t>(Const->getZExtValue())); 385b8e1544bSIlia Diachkov } 386b8e1544bSIlia Diachkov buildOpDecorate(VRegs[i][0], MIRBuilder, Dec, DecVec); 387b8e1544bSIlia Diachkov } 388b8e1544bSIlia Diachkov } 389ec259036SIlia Diachkov ++i; 390ec259036SIlia Diachkov } 391ec259036SIlia Diachkov } 392ec259036SIlia Diachkov 393eab7d363SIlia Diachkov auto MRI = MIRBuilder.getMRI(); 39467d3ef74SVyacheslav Levytskyy Register FuncVReg = MRI->createGenericVirtualRegister(LLT::scalar(64)); 395f9c98068SVyacheslav Levytskyy MRI->setRegClass(FuncVReg, &SPIRV::iIDRegClass); 396fa2a7a25SAleksandr Bezzubikov if (F.isDeclaration()) 397fa2a7a25SAleksandr Bezzubikov GR->add(&F, &MIRBuilder.getMF(), FuncVReg); 3980a443f13SVyacheslav Levytskyy FunctionType *FTy = getOriginalFunctionType(F); 399f7680835SVyacheslav Levytskyy Type *FRetTy = FTy->getReturnType(); 400f7680835SVyacheslav Levytskyy if (isUntypedPointerTy(FRetTy)) { 401f7680835SVyacheslav Levytskyy if (Type *FRetElemTy = GR->findDeducedElementType(&F)) { 4029a737109SVyacheslav Levytskyy TypedPointerType *DerivedTy = TypedPointerType::get( 4039a737109SVyacheslav Levytskyy toTypedPointer(FRetElemTy), getPointerAddressSpace(FRetTy)); 404f7680835SVyacheslav Levytskyy GR->addReturnType(&F, DerivedTy); 405f7680835SVyacheslav Levytskyy FRetTy = DerivedTy; 406f7680835SVyacheslav Levytskyy } 407f7680835SVyacheslav Levytskyy } 408f7680835SVyacheslav Levytskyy SPIRVType *RetTy = GR->getOrCreateSPIRVType(FRetTy, MIRBuilder); 4090a443f13SVyacheslav Levytskyy FTy = fixFunctionTypeIfPtrArgs(GR, F, FTy, RetTy, ArgTypeVRegs); 410b8e1544bSIlia Diachkov SPIRVType *FuncTy = GR->getOrCreateOpTypeFunctionWithArgs( 411b8e1544bSIlia Diachkov FTy, RetTy, ArgTypeVRegs, MIRBuilder); 412874b4fb6SVyacheslav Levytskyy uint32_t FuncControl = getFunctionControl(F, ST); 413eab7d363SIlia Diachkov 414d153ef6aSVyacheslav Levytskyy // Add OpFunction instruction 415d153ef6aSVyacheslav Levytskyy MachineInstrBuilder MB = MIRBuilder.buildInstr(SPIRV::OpFunction) 416ec259036SIlia Diachkov .addDef(FuncVReg) 417b8e1544bSIlia Diachkov .addUse(GR->getSPIRVTypeID(RetTy)) 418eab7d363SIlia Diachkov .addImm(FuncControl) 419eab7d363SIlia Diachkov .addUse(GR->getSPIRVTypeID(FuncTy)); 420d153ef6aSVyacheslav Levytskyy GR->recordFunctionDefinition(&F, &MB.getInstr()->getOperand(0)); 42183c1d003SVyacheslav Levytskyy GR->addGlobalObject(&F, &MIRBuilder.getMF(), FuncVReg); 422ec259036SIlia Diachkov 423d153ef6aSVyacheslav Levytskyy // Add OpFunctionParameter instructions 424b8e1544bSIlia Diachkov int i = 0; 425b8e1544bSIlia Diachkov for (const auto &Arg : F.args()) { 426ec259036SIlia Diachkov assert(VRegs[i].size() == 1 && "Formal arg has multiple vregs"); 42767d3ef74SVyacheslav Levytskyy Register ArgReg = VRegs[i][0]; 42867d3ef74SVyacheslav Levytskyy MRI->setRegClass(ArgReg, GR->getRegClass(ArgTypeVRegs[i])); 42967d3ef74SVyacheslav Levytskyy MRI->setType(ArgReg, GR->getRegType(ArgTypeVRegs[i])); 430ec259036SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpFunctionParameter) 43167d3ef74SVyacheslav Levytskyy .addDef(ArgReg) 432b8e1544bSIlia Diachkov .addUse(GR->getSPIRVTypeID(ArgTypeVRegs[i])); 433fa2a7a25SAleksandr Bezzubikov if (F.isDeclaration()) 43467d3ef74SVyacheslav Levytskyy GR->add(&Arg, &MIRBuilder.getMF(), ArgReg); 43583c1d003SVyacheslav Levytskyy GR->addGlobalObject(&Arg, &MIRBuilder.getMF(), ArgReg); 436b8e1544bSIlia Diachkov i++; 437ec259036SIlia Diachkov } 438eab7d363SIlia Diachkov // Name the function. 439eab7d363SIlia Diachkov if (F.hasName()) 440eab7d363SIlia Diachkov buildOpName(FuncVReg, F.getName(), MIRBuilder); 441eab7d363SIlia Diachkov 442eab7d363SIlia Diachkov // Handle entry points and function linkage. 44356396b25SNathan Gauër if (isEntryPoint(F)) { 444eab7d363SIlia Diachkov auto MIB = MIRBuilder.buildInstr(SPIRV::OpEntryPoint) 445874b4fb6SVyacheslav Levytskyy .addImm(static_cast<uint32_t>(getExecutionModel(*ST, F))) 446eab7d363SIlia Diachkov .addUse(FuncVReg); 447eab7d363SIlia Diachkov addStringImm(F.getName(), MIB); 4483ae63430SVyacheslav Levytskyy } else if (F.getLinkage() != GlobalValue::InternalLinkage && 4493ae63430SVyacheslav Levytskyy F.getLinkage() != GlobalValue::PrivateLinkage) { 4509552a396SVyacheslav Levytskyy SPIRV::LinkageType::LinkageType LnkTy = 4519552a396SVyacheslav Levytskyy F.isDeclaration() 4529552a396SVyacheslav Levytskyy ? SPIRV::LinkageType::Import 4539552a396SVyacheslav Levytskyy : (F.getLinkage() == GlobalValue::LinkOnceODRLinkage && 4549552a396SVyacheslav Levytskyy ST->canUseExtension( 4559552a396SVyacheslav Levytskyy SPIRV::Extension::SPV_KHR_linkonce_odr) 4569552a396SVyacheslav Levytskyy ? SPIRV::LinkageType::LinkOnceODR 4579552a396SVyacheslav Levytskyy : SPIRV::LinkageType::Export); 458eab7d363SIlia Diachkov buildOpDecorate(FuncVReg, MIRBuilder, SPIRV::Decoration::LinkageAttributes, 459eab7d363SIlia Diachkov {static_cast<uint32_t>(LnkTy)}, F.getGlobalIdentifier()); 460eab7d363SIlia Diachkov } 461eab7d363SIlia Diachkov 462d153ef6aSVyacheslav Levytskyy // Handle function pointers decoration 463d153ef6aSVyacheslav Levytskyy bool hasFunctionPointers = 464d153ef6aSVyacheslav Levytskyy ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers); 465d153ef6aSVyacheslav Levytskyy if (hasFunctionPointers) { 466d153ef6aSVyacheslav Levytskyy if (F.hasFnAttribute("referenced-indirectly")) { 467d153ef6aSVyacheslav Levytskyy assert((F.getCallingConv() != CallingConv::SPIR_KERNEL) && 468d153ef6aSVyacheslav Levytskyy "Unexpected 'referenced-indirectly' attribute of the kernel " 469d153ef6aSVyacheslav Levytskyy "function"); 470d153ef6aSVyacheslav Levytskyy buildOpDecorate(FuncVReg, MIRBuilder, 471d153ef6aSVyacheslav Levytskyy SPIRV::Decoration::ReferencedIndirectlyINTEL, {}); 472d153ef6aSVyacheslav Levytskyy } 473d153ef6aSVyacheslav Levytskyy } 474d153ef6aSVyacheslav Levytskyy 475ec259036SIlia Diachkov return true; 476ec259036SIlia Diachkov } 477ec259036SIlia Diachkov 478d153ef6aSVyacheslav Levytskyy // Used to postpone producing of indirect function pointer types after all 479d153ef6aSVyacheslav Levytskyy // indirect calls info is collected 480d153ef6aSVyacheslav Levytskyy // TODO: 481d153ef6aSVyacheslav Levytskyy // - add a topological sort of IndirectCalls to ensure the best types knowledge 482d153ef6aSVyacheslav Levytskyy // - we may need to fix function formal parameter types if they are opaque 483d153ef6aSVyacheslav Levytskyy // pointers used as function pointers in these indirect calls 484d153ef6aSVyacheslav Levytskyy void SPIRVCallLowering::produceIndirectPtrTypes( 485d153ef6aSVyacheslav Levytskyy MachineIRBuilder &MIRBuilder) const { 486d153ef6aSVyacheslav Levytskyy // Create indirect call data types if any 487d153ef6aSVyacheslav Levytskyy MachineFunction &MF = MIRBuilder.getMF(); 488d153ef6aSVyacheslav Levytskyy for (auto const &IC : IndirectCalls) { 489d153ef6aSVyacheslav Levytskyy SPIRVType *SpirvRetTy = GR->getOrCreateSPIRVType(IC.RetTy, MIRBuilder); 490d153ef6aSVyacheslav Levytskyy SmallVector<SPIRVType *, 4> SpirvArgTypes; 491d153ef6aSVyacheslav Levytskyy for (size_t i = 0; i < IC.ArgTys.size(); ++i) { 492d153ef6aSVyacheslav Levytskyy SPIRVType *SPIRVTy = GR->getOrCreateSPIRVType(IC.ArgTys[i], MIRBuilder); 493d153ef6aSVyacheslav Levytskyy SpirvArgTypes.push_back(SPIRVTy); 494d153ef6aSVyacheslav Levytskyy if (!GR->getSPIRVTypeForVReg(IC.ArgRegs[i])) 495d153ef6aSVyacheslav Levytskyy GR->assignSPIRVTypeToVReg(SPIRVTy, IC.ArgRegs[i], MF); 496d153ef6aSVyacheslav Levytskyy } 497d153ef6aSVyacheslav Levytskyy // SPIR-V function type: 498d153ef6aSVyacheslav Levytskyy FunctionType *FTy = 499d153ef6aSVyacheslav Levytskyy FunctionType::get(const_cast<Type *>(IC.RetTy), IC.ArgTys, false); 500d153ef6aSVyacheslav Levytskyy SPIRVType *SpirvFuncTy = GR->getOrCreateOpTypeFunctionWithArgs( 501d153ef6aSVyacheslav Levytskyy FTy, SpirvRetTy, SpirvArgTypes, MIRBuilder); 502d153ef6aSVyacheslav Levytskyy // SPIR-V pointer to function type: 503d153ef6aSVyacheslav Levytskyy SPIRVType *IndirectFuncPtrTy = GR->getOrCreateSPIRVPointerType( 504d153ef6aSVyacheslav Levytskyy SpirvFuncTy, MIRBuilder, SPIRV::StorageClass::Function); 5059552a396SVyacheslav Levytskyy // Correct the Callee type 506d153ef6aSVyacheslav Levytskyy GR->assignSPIRVTypeToVReg(IndirectFuncPtrTy, IC.Callee, MF); 507d153ef6aSVyacheslav Levytskyy } 508d153ef6aSVyacheslav Levytskyy } 509d153ef6aSVyacheslav Levytskyy 510ec259036SIlia Diachkov bool SPIRVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder, 511ec259036SIlia Diachkov CallLoweringInfo &Info) const { 512ec259036SIlia Diachkov // Currently call returns should have single vregs. 513ec259036SIlia Diachkov // TODO: handle the case of multiple registers. 514ec259036SIlia Diachkov if (Info.OrigRet.Regs.size() > 1) 515ec259036SIlia Diachkov return false; 516b8e1544bSIlia Diachkov MachineFunction &MF = MIRBuilder.getMF(); 517b8e1544bSIlia Diachkov GR->setCurrentFunc(MF); 518b8e1544bSIlia Diachkov const Function *CF = nullptr; 519d153ef6aSVyacheslav Levytskyy std::string DemangledName; 520d153ef6aSVyacheslav Levytskyy const Type *OrigRetTy = Info.OrigRet.Ty; 521ec259036SIlia Diachkov 522eab7d363SIlia Diachkov // Emit a regular OpFunctionCall. If it's an externally declared function, 523b8e1544bSIlia Diachkov // be sure to emit its type and function declaration here. It will be hoisted 524b8e1544bSIlia Diachkov // globally later. 525eab7d363SIlia Diachkov if (Info.Callee.isGlobal()) { 526d153ef6aSVyacheslav Levytskyy std::string FuncName = Info.Callee.getGlobal()->getName().str(); 527d153ef6aSVyacheslav Levytskyy DemangledName = getOclOrSpirvBuiltinDemangledName(FuncName); 528b8e1544bSIlia Diachkov CF = dyn_cast_or_null<const Function>(Info.Callee.getGlobal()); 529eab7d363SIlia Diachkov // TODO: support constexpr casts and indirect calls. 530eab7d363SIlia Diachkov if (CF == nullptr) 531eab7d363SIlia Diachkov return false; 532f7680835SVyacheslav Levytskyy if (FunctionType *FTy = getOriginalFunctionType(*CF)) { 533d153ef6aSVyacheslav Levytskyy OrigRetTy = FTy->getReturnType(); 534f7680835SVyacheslav Levytskyy if (isUntypedPointerTy(OrigRetTy)) { 535f7680835SVyacheslav Levytskyy if (auto *DerivedRetTy = GR->findReturnType(CF)) 536f7680835SVyacheslav Levytskyy OrigRetTy = DerivedRetTy; 537f7680835SVyacheslav Levytskyy } 538f7680835SVyacheslav Levytskyy } 539b8e1544bSIlia Diachkov } 540b8e1544bSIlia Diachkov 54174c66710SIlia Diachkov MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 542b8e1544bSIlia Diachkov Register ResVReg = 543b8e1544bSIlia Diachkov Info.OrigRet.Regs.empty() ? Register(0) : Info.OrigRet.Regs[0]; 544f61eb416SIlia Diachkov const auto *ST = static_cast<const SPIRVSubtarget *>(&MF.getSubtarget()); 545f0eb9083SNathan Gauër 546f0eb9083SNathan Gauër bool isFunctionDecl = CF && CF->isDeclaration(); 547*5810f157SMichal Paszkowski if (isFunctionDecl && !DemangledName.empty()) { 548b5132b7dSVyacheslav Levytskyy if (ResVReg.isValid()) { 549b5132b7dSVyacheslav Levytskyy if (!GR->getSPIRVTypeForVReg(ResVReg)) { 550b5132b7dSVyacheslav Levytskyy const Type *RetTy = OrigRetTy; 551b5132b7dSVyacheslav Levytskyy if (auto *PtrRetTy = dyn_cast<PointerType>(OrigRetTy)) { 552b5132b7dSVyacheslav Levytskyy const Value *OrigValue = Info.OrigRet.OrigValue; 553b5132b7dSVyacheslav Levytskyy if (!OrigValue) 554b5132b7dSVyacheslav Levytskyy OrigValue = Info.CB; 555b5132b7dSVyacheslav Levytskyy if (OrigValue) 556b5132b7dSVyacheslav Levytskyy if (Type *ElemTy = GR->findDeducedElementType(OrigValue)) 557b5132b7dSVyacheslav Levytskyy RetTy = 558b5132b7dSVyacheslav Levytskyy TypedPointerType::get(ElemTy, PtrRetTy->getAddressSpace()); 559b5132b7dSVyacheslav Levytskyy } 560b5132b7dSVyacheslav Levytskyy setRegClassType(ResVReg, RetTy, GR, MIRBuilder); 561b5132b7dSVyacheslav Levytskyy } 562b5132b7dSVyacheslav Levytskyy } else { 563b5132b7dSVyacheslav Levytskyy ResVReg = createVirtualRegister(OrigRetTy, GR, MIRBuilder); 564b5132b7dSVyacheslav Levytskyy } 565f61eb416SIlia Diachkov SmallVector<Register, 8> ArgVRegs; 566f61eb416SIlia Diachkov for (auto Arg : Info.OrigArgs) { 567f61eb416SIlia Diachkov assert(Arg.Regs.size() == 1 && "Call arg has multiple VRegs"); 56867d3ef74SVyacheslav Levytskyy Register ArgReg = Arg.Regs[0]; 56967d3ef74SVyacheslav Levytskyy ArgVRegs.push_back(ArgReg); 57067d3ef74SVyacheslav Levytskyy SPIRVType *SpvType = GR->getSPIRVTypeForVReg(ArgReg); 57167d3ef74SVyacheslav Levytskyy if (!SpvType) { 5728ac46d6bSVyacheslav Levytskyy Type *ArgTy = nullptr; 5738ac46d6bSVyacheslav Levytskyy if (auto *PtrArgTy = dyn_cast<PointerType>(Arg.Ty)) { 5748ac46d6bSVyacheslav Levytskyy // If Arg.Ty is an untyped pointer (i.e., ptr [addrspace(...)]) and we 5758ac46d6bSVyacheslav Levytskyy // don't have access to original value in LLVM IR or info about 5768ac46d6bSVyacheslav Levytskyy // deduced pointee type, then we should wait with setting the type for 5778ac46d6bSVyacheslav Levytskyy // the virtual register until pre-legalizer step when we access 5788ac46d6bSVyacheslav Levytskyy // @llvm.spv.assign.ptr.type.p...(...)'s info. 5798ac46d6bSVyacheslav Levytskyy if (Arg.OrigValue) 5808ac46d6bSVyacheslav Levytskyy if (Type *ElemTy = GR->findDeducedElementType(Arg.OrigValue)) 5818ac46d6bSVyacheslav Levytskyy ArgTy = 5828ac46d6bSVyacheslav Levytskyy TypedPointerType::get(ElemTy, PtrArgTy->getAddressSpace()); 5838ac46d6bSVyacheslav Levytskyy } else { 5848ac46d6bSVyacheslav Levytskyy ArgTy = Arg.Ty; 5858ac46d6bSVyacheslav Levytskyy } 5868ac46d6bSVyacheslav Levytskyy if (ArgTy) { 5878ac46d6bSVyacheslav Levytskyy SpvType = GR->getOrCreateSPIRVType(ArgTy, MIRBuilder); 58867d3ef74SVyacheslav Levytskyy GR->assignSPIRVTypeToVReg(SpvType, ArgReg, MF); 58967d3ef74SVyacheslav Levytskyy } 5908ac46d6bSVyacheslav Levytskyy } 59167d3ef74SVyacheslav Levytskyy if (!MRI->getRegClassOrNull(ArgReg)) { 5928ac46d6bSVyacheslav Levytskyy // Either we have SpvType created, or Arg.Ty is an untyped pointer and 5938ac46d6bSVyacheslav Levytskyy // we know its virtual register's class and type even if we don't know 5948ac46d6bSVyacheslav Levytskyy // pointee type. 5958ac46d6bSVyacheslav Levytskyy MRI->setRegClass(ArgReg, SpvType ? GR->getRegClass(SpvType) 5968ac46d6bSVyacheslav Levytskyy : &SPIRV::pIDRegClass); 5978ac46d6bSVyacheslav Levytskyy MRI->setType( 5988ac46d6bSVyacheslav Levytskyy ArgReg, 5998ac46d6bSVyacheslav Levytskyy SpvType ? GR->getRegType(SpvType) 6008ac46d6bSVyacheslav Levytskyy : LLT::pointer(cast<PointerType>(Arg.Ty)->getAddressSpace(), 6018ac46d6bSVyacheslav Levytskyy GR->getPointerSize())); 60267d3ef74SVyacheslav Levytskyy } 603f61eb416SIlia Diachkov } 604f0eb9083SNathan Gauër if (auto Res = 605*5810f157SMichal Paszkowski SPIRV::lowerBuiltin(DemangledName, ST->getPreferredInstructionSet(), 606*5810f157SMichal Paszkowski MIRBuilder, ResVReg, OrigRetTy, ArgVRegs, GR)) 6071fbc6b26SAleksandr Bezzubikov return *Res; 608f61eb416SIlia Diachkov } 609f0eb9083SNathan Gauër 610f0eb9083SNathan Gauër if (isFunctionDecl && !GR->find(CF, &MF).isValid()) { 611eab7d363SIlia Diachkov // Emit the type info and forward function declaration to the first MBB 612eab7d363SIlia Diachkov // to ensure VReg definition dependencies are valid across all MBBs. 613b8e1544bSIlia Diachkov MachineIRBuilder FirstBlockBuilder; 614b8e1544bSIlia Diachkov FirstBlockBuilder.setMF(MF); 615b8e1544bSIlia Diachkov FirstBlockBuilder.setMBB(*MF.getBlockNumbered(0)); 616eab7d363SIlia Diachkov 617eab7d363SIlia Diachkov SmallVector<ArrayRef<Register>, 8> VRegArgs; 618eab7d363SIlia Diachkov SmallVector<SmallVector<Register, 1>, 8> ToInsert; 619eab7d363SIlia Diachkov for (const Argument &Arg : CF->args()) { 620eab7d363SIlia Diachkov if (MIRBuilder.getDataLayout().getTypeStoreSize(Arg.getType()).isZero()) 621eab7d363SIlia Diachkov continue; // Don't handle zero sized types. 62267d3ef74SVyacheslav Levytskyy Register Reg = MRI->createGenericVirtualRegister(LLT::scalar(64)); 623f9c98068SVyacheslav Levytskyy MRI->setRegClass(Reg, &SPIRV::iIDRegClass); 62474c66710SIlia Diachkov ToInsert.push_back({Reg}); 625eab7d363SIlia Diachkov VRegArgs.push_back(ToInsert.back()); 626eab7d363SIlia Diachkov } 627b8e1544bSIlia Diachkov // TODO: Reuse FunctionLoweringInfo 628eab7d363SIlia Diachkov FunctionLoweringInfo FuncInfo; 629b8e1544bSIlia Diachkov lowerFormalArguments(FirstBlockBuilder, *CF, VRegArgs, FuncInfo); 630eab7d363SIlia Diachkov } 631eab7d363SIlia Diachkov 6328d8996ddSVyacheslav Levytskyy // Ignore the call if it's called from the internal service function 6338d8996ddSVyacheslav Levytskyy if (MIRBuilder.getMF() 6348d8996ddSVyacheslav Levytskyy .getFunction() 6358d8996ddSVyacheslav Levytskyy .getFnAttribute(SPIRV_BACKEND_SERVICE_FUN_NAME) 6368d8996ddSVyacheslav Levytskyy .isValid()) { 6378d8996ddSVyacheslav Levytskyy // insert a no-op 6388d8996ddSVyacheslav Levytskyy MIRBuilder.buildTrap(); 6398d8996ddSVyacheslav Levytskyy return true; 6408d8996ddSVyacheslav Levytskyy } 6418d8996ddSVyacheslav Levytskyy 642d153ef6aSVyacheslav Levytskyy unsigned CallOp; 643d153ef6aSVyacheslav Levytskyy if (Info.CB->isIndirectCall()) { 644d153ef6aSVyacheslav Levytskyy if (!ST->canUseExtension(SPIRV::Extension::SPV_INTEL_function_pointers)) 645d153ef6aSVyacheslav Levytskyy report_fatal_error("An indirect call is encountered but SPIR-V without " 646d153ef6aSVyacheslav Levytskyy "extensions does not support it", 647d153ef6aSVyacheslav Levytskyy false); 648d153ef6aSVyacheslav Levytskyy // Set instruction operation according to SPV_INTEL_function_pointers 649d153ef6aSVyacheslav Levytskyy CallOp = SPIRV::OpFunctionPointerCallINTEL; 650d153ef6aSVyacheslav Levytskyy // Collect information about the indirect call to support possible 651d153ef6aSVyacheslav Levytskyy // specification of opaque ptr types of parent function's parameters 652d153ef6aSVyacheslav Levytskyy Register CalleeReg = Info.Callee.getReg(); 653d153ef6aSVyacheslav Levytskyy if (CalleeReg.isValid()) { 654d153ef6aSVyacheslav Levytskyy SPIRVCallLowering::SPIRVIndirectCall IndirectCall; 655d153ef6aSVyacheslav Levytskyy IndirectCall.Callee = CalleeReg; 656d153ef6aSVyacheslav Levytskyy IndirectCall.RetTy = OrigRetTy; 657d153ef6aSVyacheslav Levytskyy for (const auto &Arg : Info.OrigArgs) { 658d153ef6aSVyacheslav Levytskyy assert(Arg.Regs.size() == 1 && "Call arg has multiple VRegs"); 659d153ef6aSVyacheslav Levytskyy IndirectCall.ArgTys.push_back(Arg.Ty); 660d153ef6aSVyacheslav Levytskyy IndirectCall.ArgRegs.push_back(Arg.Regs[0]); 661d153ef6aSVyacheslav Levytskyy } 662d153ef6aSVyacheslav Levytskyy IndirectCalls.push_back(IndirectCall); 663d153ef6aSVyacheslav Levytskyy } 664d153ef6aSVyacheslav Levytskyy } else { 665d153ef6aSVyacheslav Levytskyy // Emit a regular OpFunctionCall 666d153ef6aSVyacheslav Levytskyy CallOp = SPIRV::OpFunctionCall; 667d153ef6aSVyacheslav Levytskyy } 668d153ef6aSVyacheslav Levytskyy 669ec259036SIlia Diachkov // Make sure there's a valid return reg, even for functions returning void. 670b8e1544bSIlia Diachkov if (!ResVReg.isValid()) 671f9c98068SVyacheslav Levytskyy ResVReg = MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::iIDRegClass); 672d153ef6aSVyacheslav Levytskyy SPIRVType *RetType = GR->assignTypeToVReg(OrigRetTy, ResVReg, MIRBuilder); 673eab7d363SIlia Diachkov 674d153ef6aSVyacheslav Levytskyy // Emit the call instruction and its args. 675d153ef6aSVyacheslav Levytskyy auto MIB = MIRBuilder.buildInstr(CallOp) 676ec259036SIlia Diachkov .addDef(ResVReg) 677eab7d363SIlia Diachkov .addUse(GR->getSPIRVTypeID(RetType)) 678ec259036SIlia Diachkov .add(Info.Callee); 679ec259036SIlia Diachkov 680ec259036SIlia Diachkov for (const auto &Arg : Info.OrigArgs) { 681ec259036SIlia Diachkov // Currently call args should have single vregs. 682ec259036SIlia Diachkov if (Arg.Regs.size() > 1) 683ec259036SIlia Diachkov return false; 684ec259036SIlia Diachkov MIB.addUse(Arg.Regs[0]); 685ec259036SIlia Diachkov } 686f61eb416SIlia Diachkov return MIB.constrainAllUses(MIRBuilder.getTII(), *ST->getRegisterInfo(), 687f61eb416SIlia Diachkov *ST->getRegBankInfo()); 688ec259036SIlia Diachkov } 689