20#include "llvm/IR/IntrinsicsSPIRV.h"
24#define DEBUG_TYPE "spirv-builtins"
28#define GET_BuiltinGroup_DECL
29#include "SPIRVGenTables.inc"
33 InstructionSet::InstructionSet
Set;
39#define GET_DemangledBuiltins_DECL
40#define GET_DemangledBuiltins_IMPL
62 InstructionSet::InstructionSet
Set;
66#define GET_NativeBuiltins_DECL
67#define GET_NativeBuiltins_IMPL
85#define GET_GroupBuiltins_DECL
86#define GET_GroupBuiltins_IMPL
95#define GET_IntelSubgroupsBuiltins_DECL
96#define GET_IntelSubgroupsBuiltins_IMPL
103#define GET_AtomicFloatingBuiltins_DECL
104#define GET_AtomicFloatingBuiltins_IMPL
111#define GET_GroupUniformBuiltins_DECL
112#define GET_GroupUniformBuiltins_IMPL
116 InstructionSet::InstructionSet
Set;
120using namespace BuiltIn;
121#define GET_GetBuiltins_DECL
122#define GET_GetBuiltins_IMPL
126 InstructionSet::InstructionSet
Set;
130#define GET_ImageQueryBuiltins_DECL
131#define GET_ImageQueryBuiltins_IMPL
135 InstructionSet::InstructionSet
Set;
145 InstructionSet::InstructionSet
Set;
152using namespace FPRoundingMode;
153#define GET_ConvertBuiltins_DECL
154#define GET_ConvertBuiltins_IMPL
156using namespace InstructionSet;
157#define GET_VectorLoadStoreBuiltins_DECL
158#define GET_VectorLoadStoreBuiltins_IMPL
160#define GET_CLMemoryScope_DECL
161#define GET_CLSamplerAddressingMode_DECL
162#define GET_CLMemoryFenceFlags_DECL
163#define GET_ExtendedBuiltins_DECL
164#include "SPIRVGenTables.inc"
182static std::unique_ptr<const SPIRV::IncomingCall>
184 SPIRV::InstructionSet::InstructionSet Set,
189 std::string BuiltinName =
193 if (BuiltinName.rfind(
"__spirv_ocl_", 0) == 0)
194 BuiltinName = BuiltinName.substr(12);
199 if (BuiltinName.find(
'<') && BuiltinName.back() ==
'>') {
200 BuiltinName = BuiltinName.substr(0, BuiltinName.find(
'<'));
201 BuiltinName = BuiltinName.substr(BuiltinName.find_last_of(
' ') + 1);
209 BuiltinName = BuiltinName.substr(0, BuiltinName.find(
"_R"));
214 DemangledCall.
slice(DemangledCall.
find(
'(') + 1, DemangledCall.
find(
')'));
215 BuiltinArgs.
split(BuiltinArgumentTypes,
',', -1,
false);
220 if ((Builtin = SPIRV::lookupBuiltin(BuiltinName, Set)))
221 return std::make_unique<SPIRV::IncomingCall>(
222 BuiltinName, Builtin, ReturnRegister, ReturnType,
Arguments);
227 if (BuiltinArgumentTypes.
size() >= 1) {
228 char FirstArgumentType = BuiltinArgumentTypes[0][0];
233 switch (FirstArgumentType) {
236 if (Set == SPIRV::InstructionSet::OpenCL_std)
238 else if (Set == SPIRV::InstructionSet::GLSL_std_450)
246 if (Set == SPIRV::InstructionSet::OpenCL_std)
248 else if (Set == SPIRV::InstructionSet::GLSL_std_450)
255 if (Set == SPIRV::InstructionSet::OpenCL_std ||
256 Set == SPIRV::InstructionSet::GLSL_std_450)
262 if (!Prefix.empty() &&
263 (Builtin = SPIRV::lookupBuiltin(Prefix + BuiltinName, Set)))
264 return std::make_unique<SPIRV::IncomingCall>(
265 BuiltinName, Builtin, ReturnRegister, ReturnType,
Arguments);
272 switch (FirstArgumentType) {
293 if (!Suffix.empty() &&
294 (Builtin = SPIRV::lookupBuiltin(BuiltinName + Suffix, Set)))
295 return std::make_unique<SPIRV::IncomingCall>(
296 BuiltinName, Builtin, ReturnRegister, ReturnType,
Arguments);
311static std::tuple<Register, SPIRVType *>
317 if (ResultType->
getOpcode() == SPIRV::OpTypeVector) {
332 return std::make_tuple(ResultRegister, BoolType);
343 if (ReturnType->getOpcode() == SPIRV::OpTypeVector) {
352 return MIRBuilder.
buildSelect(ReturnRegister, SourceRegister, TrueConst,
363 if (!DestinationReg.isValid()) {
364 DestinationReg =
MRI->createVirtualRegister(&SPIRV::IDRegClass);
371 MIRBuilder.
buildLoad(DestinationReg, PtrRegister, PtrInfo,
Align());
372 return DestinationReg;
386 VariableType, MIRBuilder, SPIRV::StorageClass::Input);
392 SPIRV::StorageClass::Input,
nullptr, isConst,
393 hasLinkageTy, SPIRV::LinkageType::Import, MIRBuilder,
400 return LoadedRegister;
409 SPIRVGlobalRegistry *GR,
410 MachineIRBuilder &MIB,
411 MachineRegisterInfo &
MRI);
414static SPIRV::MemorySemantics::MemorySemantics
417 case std::memory_order::memory_order_relaxed:
418 return SPIRV::MemorySemantics::None;
419 case std::memory_order::memory_order_acquire:
420 return SPIRV::MemorySemantics::Acquire;
421 case std::memory_order::memory_order_release:
422 return SPIRV::MemorySemantics::Release;
423 case std::memory_order::memory_order_acq_rel:
424 return SPIRV::MemorySemantics::AcquireRelease;
425 case std::memory_order::memory_order_seq_cst:
426 return SPIRV::MemorySemantics::SequentiallyConsistent;
434 case SPIRV::CLMemoryScope::memory_scope_work_item:
435 return SPIRV::Scope::Invocation;
436 case SPIRV::CLMemoryScope::memory_scope_work_group:
437 return SPIRV::Scope::Workgroup;
438 case SPIRV::CLMemoryScope::memory_scope_device:
439 return SPIRV::Scope::Device;
440 case SPIRV::CLMemoryScope::memory_scope_all_svm_devices:
441 return SPIRV::Scope::CrossDevice;
442 case SPIRV::CLMemoryScope::memory_scope_sub_group:
443 return SPIRV::Scope::Subgroup;
456 SPIRV::Scope::Scope Scope,
460 if (CLScopeRegister.
isValid()) {
465 if (CLScope ==
static_cast<unsigned>(Scope)) {
466 MRI->setRegClass(CLScopeRegister, &SPIRV::IDRegClass);
467 return CLScopeRegister;
474 Register PtrRegister,
unsigned &Semantics,
477 if (SemanticsRegister.
isValid()) {
479 std::memory_order Order =
485 if (Order == Semantics) {
486 MRI->setRegClass(SemanticsRegister, &SPIRV::IDRegClass);
487 return SemanticsRegister;
498 if (TypeReg.isValid())
500 for (
Register ArgReg : Call->Arguments) {
501 if (!
MRI->getRegClassOrNull(ArgReg))
502 MRI->setRegClass(ArgReg, &SPIRV::IDRegClass);
511 if (Call->isSpirvOp())
514 assert(Call->Arguments.size() == 2 &&
515 "Need 2 arguments for atomic init translation");
519 .
addUse(Call->Arguments[0])
520 .
addUse(Call->Arguments[1]);
529 if (Call->isSpirvOp())
532 Register PtrRegister = Call->Arguments[0];
538 if (Call->Arguments.size() > 1) {
539 ScopeRegister = Call->Arguments[1];
545 if (Call->Arguments.size() > 2) {
547 MemSemanticsReg = Call->Arguments[2];
551 SPIRV::MemorySemantics::SequentiallyConsistent |
557 .
addDef(Call->ReturnRegister)
569 if (Call->isSpirvOp())
574 Register PtrRegister = Call->Arguments[0];
577 SPIRV::MemorySemantics::SequentiallyConsistent |
585 .
addUse(Call->Arguments[1]);
593 if (Call->isSpirvOp())
597 bool IsCmpxchg = Call->Builtin->Name.contains(
"cmpxchg");
600 Register ObjectPtr = Call->Arguments[0];
601 Register ExpectedArg = Call->Arguments[1];
602 Register Desired = Call->Arguments[2];
603 MRI->setRegClass(ObjectPtr, &SPIRV::IDRegClass);
604 MRI->setRegClass(ExpectedArg, &SPIRV::IDRegClass);
605 MRI->setRegClass(Desired, &SPIRV::IDRegClass);
607 LLT DesiredLLT =
MRI->getType(Desired);
610 SPIRV::OpTypePointer);
613 assert(IsCmpxchg ? ExpectedType == SPIRV::OpTypeInt
614 : ExpectedType == SPIRV::OpTypePointer);
619 auto StorageClass =
static_cast<SPIRV::StorageClass::StorageClass
>(
627 ? SPIRV::MemorySemantics::None
628 : SPIRV::MemorySemantics::SequentiallyConsistent | MemSemStorage;
631 ? SPIRV::MemorySemantics::None
632 : SPIRV::MemorySemantics::SequentiallyConsistent | MemSemStorage;
633 if (Call->Arguments.size() >= 4) {
634 assert(Call->Arguments.size() >= 5 &&
635 "Need 5+ args for explicit atomic cmpxchg");
642 if (MemOrdEq == MemSemEqual)
643 MemSemEqualReg = Call->Arguments[3];
644 if (MemOrdNeq == MemSemEqual)
645 MemSemUnequalReg = Call->Arguments[4];
646 MRI->setRegClass(Call->Arguments[3], &SPIRV::IDRegClass);
647 MRI->setRegClass(Call->Arguments[4], &SPIRV::IDRegClass);
651 if (!MemSemUnequalReg.
isValid())
655 auto Scope = IsCmpxchg ? SPIRV::Scope::Workgroup : SPIRV::Scope::Device;
656 if (Call->Arguments.size() >= 6) {
657 assert(Call->Arguments.size() == 6 &&
658 "Extra args for explicit atomic cmpxchg");
659 auto ClScope =
static_cast<SPIRV::CLMemoryScope
>(
662 if (ClScope ==
static_cast<unsigned>(Scope))
663 ScopeReg = Call->Arguments[5];
664 MRI->setRegClass(Call->Arguments[5], &SPIRV::IDRegClass);
674 Register Tmp = !IsCmpxchg ?
MRI->createGenericVirtualRegister(DesiredLLT)
675 : Call->ReturnRegister;
676 if (!
MRI->getRegClassOrNull(Tmp))
677 MRI->setRegClass(Tmp, &SPIRV::IDRegClass);
701 if (Call->isSpirvOp())
707 Call->Arguments.size() >= 4 ? Call->Arguments[3] :
Register();
709 assert(Call->Arguments.size() <= 4 &&
710 "Too many args for explicit atomic RMW");
711 ScopeRegister =
buildScopeReg(ScopeRegister, SPIRV::Scope::Workgroup,
712 MIRBuilder, GR,
MRI);
714 Register PtrRegister = Call->Arguments[0];
715 unsigned Semantics = SPIRV::MemorySemantics::None;
716 MRI->setRegClass(PtrRegister, &SPIRV::IDRegClass);
718 Call->Arguments.size() >= 3 ? Call->Arguments[2] :
Register();
720 Semantics, MIRBuilder, GR);
721 MRI->setRegClass(Call->Arguments[1], &SPIRV::IDRegClass);
723 .
addDef(Call->ReturnRegister)
728 .
addUse(Call->Arguments[1]);
737 assert(Call->Arguments.size() == 4 &&
738 "Wrong number of atomic floating-type builtin");
742 Register PtrReg = Call->Arguments[0];
743 MRI->setRegClass(PtrReg, &SPIRV::IDRegClass);
745 Register ScopeReg = Call->Arguments[1];
746 MRI->setRegClass(ScopeReg, &SPIRV::IDRegClass);
748 Register MemSemanticsReg = Call->Arguments[2];
749 MRI->setRegClass(MemSemanticsReg, &SPIRV::IDRegClass);
751 Register ValueReg = Call->Arguments[3];
752 MRI->setRegClass(ValueReg, &SPIRV::IDRegClass);
755 .
addDef(Call->ReturnRegister)
769 bool IsSet = Opcode == SPIRV::OpAtomicFlagTestAndSet;
771 if (Call->isSpirvOp())
776 Register PtrRegister = Call->Arguments[0];
777 unsigned Semantics = SPIRV::MemorySemantics::SequentiallyConsistent;
779 Call->Arguments.size() >= 2 ? Call->Arguments[1] :
Register();
781 Semantics, MIRBuilder, GR);
783 assert((Opcode != SPIRV::OpAtomicFlagClear ||
784 (Semantics != SPIRV::MemorySemantics::Acquire &&
785 Semantics != SPIRV::MemorySemantics::AcquireRelease)) &&
786 "Invalid memory order argument!");
789 Call->Arguments.size() >= 3 ? Call->Arguments[2] :
Register();
806 if (Call->isSpirvOp())
811 unsigned MemSemantics = SPIRV::MemorySemantics::None;
813 if (MemFlags & SPIRV::CLK_LOCAL_MEM_FENCE)
814 MemSemantics |= SPIRV::MemorySemantics::WorkgroupMemory;
816 if (MemFlags & SPIRV::CLK_GLOBAL_MEM_FENCE)
817 MemSemantics |= SPIRV::MemorySemantics::CrossWorkgroupMemory;
819 if (MemFlags & SPIRV::CLK_IMAGE_MEM_FENCE)
820 MemSemantics |= SPIRV::MemorySemantics::ImageMemory;
822 if (Opcode == SPIRV::OpMemoryBarrier) {
823 std::memory_order MemOrder =
827 MemSemantics |= SPIRV::MemorySemantics::SequentiallyConsistent;
831 if (MemFlags == MemSemantics) {
832 MemSemanticsReg = Call->Arguments[0];
833 MRI->setRegClass(MemSemanticsReg, &SPIRV::IDRegClass);
838 SPIRV::Scope::Scope Scope = SPIRV::Scope::Workgroup;
839 SPIRV::Scope::Scope MemScope = Scope;
840 if (Call->Arguments.size() >= 2) {
842 ((Opcode != SPIRV::OpMemoryBarrier && Call->Arguments.size() == 2) ||
843 (Opcode == SPIRV::OpMemoryBarrier && Call->Arguments.size() == 3)) &&
844 "Extra args for explicitly scoped barrier");
845 Register ScopeArg = (Opcode == SPIRV::OpMemoryBarrier) ? Call->Arguments[2]
846 : Call->Arguments[1];
847 SPIRV::CLMemoryScope CLScope =
850 if (!(MemFlags & SPIRV::CLK_LOCAL_MEM_FENCE) ||
851 (Opcode == SPIRV::OpMemoryBarrier))
854 if (CLScope ==
static_cast<unsigned>(Scope)) {
855 ScopeReg = Call->Arguments[1];
856 MRI->setRegClass(ScopeReg, &SPIRV::IDRegClass);
864 if (Opcode != SPIRV::OpMemoryBarrier)
866 MIB.
addUse(MemSemanticsReg);
872 case SPIRV::Dim::DIM_1D:
873 case SPIRV::Dim::DIM_Buffer:
875 case SPIRV::Dim::DIM_2D:
876 case SPIRV::Dim::DIM_Cube:
877 case SPIRV::Dim::DIM_Rect:
879 case SPIRV::Dim::DIM_3D:
892 return arrayed ? numComps + 1 : numComps;
905 SPIRV::lookupExtendedBuiltin(Builtin->
Name, Builtin->
Set)->Number;
910 .
addDef(Call->ReturnRegister)
915 for (
auto Argument : Call->Arguments)
926 SPIRV::lookupNativeBuiltin(Builtin->
Name, Builtin->
Set)->Opcode;
930 std::tie(CompareRegister, RelationType) =
938 for (
auto Argument : Call->Arguments)
942 return buildSelectInst(MIRBuilder, Call->ReturnRegister, CompareRegister,
943 Call->ReturnType, GR);
951 SPIRV::lookupGroupBuiltin(Builtin->
Name);
955 Register ConstRegister = Call->Arguments[0];
957 (void)ArgInstruction;
959 assert(ArgInstruction->getOpcode() == TargetOpcode::G_CONSTANT &&
960 "Only constant bool value args are supported");
967 Register GroupResultRegister = Call->ReturnRegister;
968 SPIRVType *GroupResultType = Call->ReturnType;
972 const bool HasBoolReturnTy =
978 std::tie(GroupResultRegister, GroupResultType) =
981 auto Scope = Builtin->
Name.
starts_with(
"sub_group") ? SPIRV::Scope::Subgroup
982 : SPIRV::Scope::Workgroup;
987 .
addDef(GroupResultRegister)
993 if (Call->Arguments.size() > 0) {
995 MRI->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
996 for (
unsigned i = 1; i < Call->Arguments.size(); i++) {
997 MIB.addUse(Call->Arguments[i]);
998 MRI->setRegClass(Call->Arguments[i], &SPIRV::IDRegClass);
1003 if (HasBoolReturnTy)
1004 buildSelectInst(MIRBuilder, Call->ReturnRegister, GroupResultRegister,
1005 Call->ReturnType, GR);
1015 if (!ST->canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) {
1016 std::string DiagMsg = std::string(Builtin->
Name) +
1017 ": the builtin requires the following SPIR-V "
1018 "extension: SPV_INTEL_subgroups";
1022 SPIRV::lookupIntelSubgroupsBuiltin(Builtin->
Name);
1026 if (IntelSubgroups->
IsBlock) {
1029 if (Arg0Type->getOpcode() == SPIRV::OpTypeImage) {
1035 case SPIRV::OpSubgroupBlockReadINTEL:
1036 OpCode = SPIRV::OpSubgroupImageBlockReadINTEL;
1038 case SPIRV::OpSubgroupBlockWriteINTEL:
1039 OpCode = SPIRV::OpSubgroupImageBlockWriteINTEL;
1060 .
addDef(Call->ReturnRegister)
1062 for (
size_t i = 0; i < Call->Arguments.size(); ++i) {
1063 MIB.
addUse(Call->Arguments[i]);
1064 MRI->setRegClass(Call->Arguments[i], &SPIRV::IDRegClass);
1076 if (!ST->canUseExtension(
1077 SPIRV::Extension::SPV_KHR_uniform_group_instructions)) {
1078 std::string DiagMsg = std::string(Builtin->
Name) +
1079 ": the builtin requires the following SPIR-V "
1080 "extension: SPV_KHR_uniform_group_instructions";
1084 SPIRV::lookupGroupUniformBuiltin(Builtin->
Name);
1087 Register GroupResultReg = Call->ReturnRegister;
1088 MRI->setRegClass(GroupResultReg, &SPIRV::IDRegClass);
1091 Register ScopeReg = Call->Arguments[0];
1092 MRI->setRegClass(ScopeReg, &SPIRV::IDRegClass);
1095 Register ConstGroupOpReg = Call->Arguments[1];
1097 if (!Const || Const->getOpcode() != TargetOpcode::G_CONSTANT)
1099 "expect a constant group operation for a uniform group instruction",
1102 if (!ConstOperand.
isCImm())
1108 Register ValueReg = Call->Arguments[2];
1109 MRI->setRegClass(ValueReg, &SPIRV::IDRegClass);
1116 MIB.addUse(ValueReg);
1150 SPIRV::BuiltIn::BuiltIn BuiltinValue,
1152 Register IndexRegister = Call->Arguments[0];
1153 const unsigned ResultWidth = Call->ReturnType->getOperand(1).getImm();
1161 Register ToTruncate = Call->ReturnRegister;
1164 bool IsConstantIndex =
1165 IndexInstruction->getOpcode() == TargetOpcode::G_CONSTANT;
1170 Register DefaultReg = Call->ReturnRegister;
1171 if (PointerSize != ResultWidth) {
1172 DefaultReg =
MRI->createGenericVirtualRegister(
LLT::scalar(PointerSize));
1173 MRI->setRegClass(DefaultReg, &SPIRV::IDRegClass);
1175 MIRBuilder.
getMF());
1176 ToTruncate = DefaultReg;
1180 MIRBuilder.
buildCopy(DefaultReg, NewRegister);
1188 Register Extracted = Call->ReturnRegister;
1189 if (!IsConstantIndex || PointerSize != ResultWidth) {
1190 Extracted =
MRI->createGenericVirtualRegister(
LLT::scalar(PointerSize));
1191 MRI->setRegClass(Extracted, &SPIRV::IDRegClass);
1198 ExtractInst.
addUse(LoadedVector).
addUse(IndexRegister);
1201 if (!IsConstantIndex) {
1210 MRI->setRegClass(CompareRegister, &SPIRV::IDRegClass);
1223 Register SelectionResult = Call->ReturnRegister;
1224 if (PointerSize != ResultWidth) {
1227 MRI->setRegClass(SelectionResult, &SPIRV::IDRegClass);
1229 MIRBuilder.
getMF());
1232 MIRBuilder.
buildSelect(SelectionResult, CompareRegister, Extracted,
1234 ToTruncate = SelectionResult;
1236 ToTruncate = Extracted;
1240 if (PointerSize != ResultWidth)
1250 SPIRV::BuiltIn::BuiltIn
Value =
1251 SPIRV::lookupGetBuiltin(Builtin->
Name, Builtin->
Set)->
Value;
1253 if (
Value == SPIRV::BuiltIn::GlobalInvocationId)
1259 if (Call->ReturnType->getOpcode() == SPIRV::OpTypeVector)
1266 LLType, Call->ReturnRegister);
1275 SPIRV::lookupNativeBuiltin(Builtin->
Name, Builtin->
Set)->Opcode;
1278 case SPIRV::OpStore:
1280 case SPIRV::OpAtomicLoad:
1282 case SPIRV::OpAtomicStore:
1284 case SPIRV::OpAtomicCompareExchange:
1285 case SPIRV::OpAtomicCompareExchangeWeak:
1288 case SPIRV::OpAtomicIAdd:
1289 case SPIRV::OpAtomicISub:
1290 case SPIRV::OpAtomicOr:
1291 case SPIRV::OpAtomicXor:
1292 case SPIRV::OpAtomicAnd:
1293 case SPIRV::OpAtomicExchange:
1295 case SPIRV::OpMemoryBarrier:
1297 case SPIRV::OpAtomicFlagTestAndSet:
1298 case SPIRV::OpAtomicFlagClear:
1310 unsigned Opcode = SPIRV::lookupAtomicFloatingBuiltin(Builtin->
Name)->Opcode;
1313 case SPIRV::OpAtomicFAddEXT:
1314 case SPIRV::OpAtomicFMinEXT:
1315 case SPIRV::OpAtomicFMaxEXT:
1328 SPIRV::lookupNativeBuiltin(Builtin->
Name, Builtin->
Set)->Opcode;
1337 bool IsVec = Opcode == SPIRV::OpTypeVector;
1339 MIRBuilder.
buildInstr(IsVec ? SPIRV::OpDot : SPIRV::OpFMulS)
1340 .
addDef(Call->ReturnRegister)
1342 .
addUse(Call->Arguments[0])
1343 .
addUse(Call->Arguments[1]);
1351 SPIRV::BuiltIn::BuiltIn
Value =
1352 SPIRV::lookupGetBuiltin(Builtin->
Name, Builtin->
Set)->
Value;
1355 assert(Call->ReturnType->getOpcode() == SPIRV::OpTypeInt);
1359 MIRBuilder, Call->ReturnType, GR,
Value, LLType, Call->ReturnRegister,
1367 SPIRV::BuiltIn::BuiltIn
Value =
1368 SPIRV::lookupGetBuiltin(Call->Builtin->Name, Call->Builtin->Set)->
Value;
1369 uint64_t IsDefault = (
Value == SPIRV::BuiltIn::GlobalSize ||
1370 Value == SPIRV::BuiltIn::WorkgroupSize ||
1371 Value == SPIRV::BuiltIn::EnqueuedWorkgroupSize);
1381 SPIRV::lookupImageQueryBuiltin(Builtin->
Name, Builtin->
Set)->Component;
1386 unsigned NumExpectedRetComponents =
RetTy->getOpcode() == SPIRV::OpTypeVector
1387 ?
RetTy->getOperand(2).getImm()
1392 Register QueryResult = Call->ReturnRegister;
1393 SPIRVType *QueryResultType = Call->ReturnType;
1394 if (NumExpectedRetComponents != NumActualRetComponents) {
1400 IntTy, NumActualRetComponents, MIRBuilder);
1405 IsDimBuf ? SPIRV::OpImageQuerySize : SPIRV::OpImageQuerySizeLod;
1410 .
addUse(Call->Arguments[0]);
1413 if (NumExpectedRetComponents == NumActualRetComponents)
1415 if (NumExpectedRetComponents == 1) {
1417 unsigned ExtractedComposite =
1418 Component == 3 ? NumActualRetComponents - 1 : Component;
1419 assert(ExtractedComposite < NumActualRetComponents &&
1420 "Invalid composite index!");
1421 MIRBuilder.
buildInstr(SPIRV::OpCompositeExtract)
1422 .
addDef(Call->ReturnRegister)
1425 .
addImm(ExtractedComposite);
1428 auto MIB = MIRBuilder.
buildInstr(SPIRV::OpVectorShuffle)
1429 .
addDef(Call->ReturnRegister)
1433 for (
unsigned i = 0; i < NumExpectedRetComponents; ++i)
1434 MIB.
addImm(i < NumActualRetComponents ? i : 0xffffffff);
1442 assert(Call->ReturnType->getOpcode() == SPIRV::OpTypeInt &&
1443 "Image samples query result must be of int type!");
1448 SPIRV::lookupNativeBuiltin(Builtin->
Name, Builtin->
Set)->Opcode;
1450 Register Image = Call->Arguments[0];
1452 SPIRV::Dim::Dim ImageDimensionality =
static_cast<SPIRV::Dim::Dim
>(
1454 (void)ImageDimensionality;
1457 case SPIRV::OpImageQuerySamples:
1458 assert(ImageDimensionality == SPIRV::Dim::DIM_2D &&
1459 "Image must be of 2D dimensionality");
1461 case SPIRV::OpImageQueryLevels:
1462 assert((ImageDimensionality == SPIRV::Dim::DIM_1D ||
1463 ImageDimensionality == SPIRV::Dim::DIM_2D ||
1464 ImageDimensionality == SPIRV::Dim::DIM_3D ||
1465 ImageDimensionality == SPIRV::Dim::DIM_Cube) &&
1466 "Image must be of 1D/2D/3D/Cube dimensionality");
1471 .
addDef(Call->ReturnRegister)
1478static SPIRV::SamplerAddressingMode::SamplerAddressingMode
1480 switch (Bitmask & SPIRV::CLK_ADDRESS_MODE_MASK) {
1481 case SPIRV::CLK_ADDRESS_CLAMP:
1482 return SPIRV::SamplerAddressingMode::Clamp;
1483 case SPIRV::CLK_ADDRESS_CLAMP_TO_EDGE:
1484 return SPIRV::SamplerAddressingMode::ClampToEdge;
1485 case SPIRV::CLK_ADDRESS_REPEAT:
1486 return SPIRV::SamplerAddressingMode::Repeat;
1487 case SPIRV::CLK_ADDRESS_MIRRORED_REPEAT:
1488 return SPIRV::SamplerAddressingMode::RepeatMirrored;
1489 case SPIRV::CLK_ADDRESS_NONE:
1490 return SPIRV::SamplerAddressingMode::None;
1497 return (Bitmask & SPIRV::CLK_NORMALIZED_COORDS_TRUE) ? 1 : 0;
1500static SPIRV::SamplerFilterMode::SamplerFilterMode
1502 if (Bitmask & SPIRV::CLK_FILTER_LINEAR)
1503 return SPIRV::SamplerFilterMode::Linear;
1504 if (Bitmask & SPIRV::CLK_FILTER_NEAREST)
1505 return SPIRV::SamplerFilterMode::Nearest;
1506 return SPIRV::SamplerFilterMode::Nearest;
1513 Register Image = Call->Arguments[0];
1515 MRI->setRegClass(Image, &SPIRV::IDRegClass);
1516 MRI->setRegClass(Call->Arguments[1], &SPIRV::IDRegClass);
1519 if (HasOclSampler || HasMsaa)
1520 MRI->setRegClass(Call->Arguments[2], &SPIRV::IDRegClass);
1521 if (HasOclSampler) {
1522 Register Sampler = Call->Arguments[1];
1536 Register SampledImage =
MRI->createVirtualRegister(&SPIRV::IDRegClass);
1547 bool NeedsExtraction =
false;
1548 if (TempType->
getOpcode() != SPIRV::OpTypeVector) {
1551 NeedsExtraction =
true;
1554 Register TempRegister =
MRI->createGenericVirtualRegister(LLType);
1555 MRI->setRegClass(TempRegister, &SPIRV::IDRegClass);
1558 MIRBuilder.
buildInstr(SPIRV::OpImageSampleExplicitLod)
1559 .
addDef(NeedsExtraction ? TempRegister : Call->ReturnRegister)
1562 .
addUse(Call->Arguments[2])
1563 .
addImm(SPIRV::ImageOperand::Lod)
1566 if (NeedsExtraction)
1567 MIRBuilder.
buildInstr(SPIRV::OpCompositeExtract)
1568 .
addDef(Call->ReturnRegister)
1572 }
else if (HasMsaa) {
1574 .
addDef(Call->ReturnRegister)
1577 .
addUse(Call->Arguments[1])
1578 .
addImm(SPIRV::ImageOperand::Sample)
1579 .
addUse(Call->Arguments[2]);
1582 .
addDef(Call->ReturnRegister)
1585 .
addUse(Call->Arguments[1]);
1597 .
addUse(Call->Arguments[0])
1598 .
addUse(Call->Arguments[1])
1599 .
addUse(Call->Arguments[2]);
1608 if (Call->Builtin->Name.contains_insensitive(
1609 "__translate_sampler_initializer")) {
1616 return Sampler.isValid();
1617 }
else if (Call->Builtin->Name.contains_insensitive(
"__spirv_SampledImage")) {
1619 Register Image = Call->Arguments[0];
1624 Call->ReturnRegister.isValid()
1625 ? Call->ReturnRegister
1626 :
MRI->createVirtualRegister(&SPIRV::IDRegClass);
1631 .
addUse(Call->Arguments[1]);
1633 }
else if (Call->Builtin->Name.contains_insensitive(
1634 "__spirv_ImageSampleExplicitLod")) {
1636 std::string ReturnType = DemangledCall.
str();
1637 if (DemangledCall.
contains(
"_R")) {
1638 ReturnType = ReturnType.substr(ReturnType.find(
"_R") + 2);
1639 ReturnType = ReturnType.substr(0, ReturnType.find(
'('));
1646 std::string DiagMsg =
1647 "Unable to recognize SPIRV type name: " + ReturnType;
1650 MRI->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
1651 MRI->setRegClass(Call->Arguments[1], &SPIRV::IDRegClass);
1652 MRI->setRegClass(Call->Arguments[3], &SPIRV::IDRegClass);
1654 MIRBuilder.
buildInstr(SPIRV::OpImageSampleExplicitLod)
1655 .
addDef(Call->ReturnRegister)
1657 .
addUse(Call->Arguments[0])
1658 .
addUse(Call->Arguments[1])
1659 .
addImm(SPIRV::ImageOperand::Lod)
1660 .
addUse(Call->Arguments[3]);
1668 MIRBuilder.
buildSelect(Call->ReturnRegister, Call->Arguments[0],
1669 Call->Arguments[1], Call->Arguments[2]);
1679 SPIRV::lookupNativeBuiltin(Builtin->
Name, Builtin->
Set)->Opcode;
1683 case SPIRV::OpSpecConstant: {
1687 buildOpDecorate(Call->ReturnRegister, MIRBuilder, SPIRV::Decoration::SpecId,
1690 Register ConstRegister = Call->Arguments[1];
1693 (Const->getOpcode() == TargetOpcode::G_CONSTANT ||
1694 Const->getOpcode() == TargetOpcode::G_FCONSTANT) &&
1695 "Argument should be either an int or floating-point constant");
1698 if (Call->ReturnType->getOpcode() == SPIRV::OpTypeBool) {
1699 assert(ConstOperand.
isCImm() &&
"Int constant operand is expected");
1701 ? SPIRV::OpSpecConstantTrue
1702 : SPIRV::OpSpecConstantFalse;
1705 .
addDef(Call->ReturnRegister)
1708 if (Call->ReturnType->getOpcode() != SPIRV::OpTypeBool) {
1709 if (Const->getOpcode() == TargetOpcode::G_CONSTANT)
1716 case SPIRV::OpSpecConstantComposite: {
1718 .
addDef(Call->ReturnRegister)
1720 for (
unsigned i = 0; i < Call->Arguments.size(); i++)
1721 MIB.
addUse(Call->Arguments[i]);
1733 MRI->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
1740 Register TmpReg =
MRI->createVirtualRegister(&SPIRV::IDRegClass);
1744 unsigned NumArgs = Call->Arguments.size();
1746 Register GlobalWorkSize = Call->Arguments[NumArgs < 4 ? 1 : 2];
1747 MRI->setRegClass(GlobalWorkSize, &SPIRV::IDRegClass);
1749 NumArgs == 2 ?
Register(0) : Call->Arguments[NumArgs < 4 ? 2 : 3];
1751 MRI->setRegClass(LocalWorkSize, &SPIRV::IDRegClass);
1752 Register GlobalWorkOffset = NumArgs <= 3 ?
Register(0) : Call->Arguments[1];
1753 if (GlobalWorkOffset.
isValid())
1754 MRI->setRegClass(GlobalWorkOffset, &SPIRV::IDRegClass);
1758 if (SpvTy->
getOpcode() == SPIRV::OpTypePointer) {
1763 if (!
MRI->getRegClassOrNull(GWSPtr))
1764 MRI->setRegClass(GWSPtr, &SPIRV::IDRegClass);
1766 unsigned Size = Call->Builtin->Name ==
"ndrange_3D" ? 3 : 2;
1771 GlobalWorkSize =
MRI->createVirtualRegister(&SPIRV::IDRegClass);
1782 LocalWorkSize = Const;
1783 if (!GlobalWorkOffset.
isValid())
1784 GlobalWorkOffset = Const;
1792 .
addUse(GlobalWorkOffset);
1794 .
addUse(Call->Arguments[0])
1806 assert(
MI->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST &&
1807 MI->getOperand(1).isReg());
1808 Register BitcastReg =
MI->getOperand(1).getReg();
1836 Register ValueReg =
MI->getOperand(0).getReg();
1841 assert(Ty &&
"Type is expected");
1853 if (
MI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE)
1854 return MI->getOperand(1).getGlobal()->getType();
1856 "Blocks in OpenCL C must be traceable to allocation site");
1881 bool IsSpirvOp = Call->isSpirvOp();
1882 bool HasEvents = Call->Builtin->Name.contains(
"events") || IsSpirvOp;
1889 if (Call->Builtin->Name.find(
"_varargs") !=
StringRef::npos || IsSpirvOp) {
1890 const unsigned LocalSizeArrayIdx = HasEvents ? 9 : 6;
1891 Register GepReg = Call->Arguments[LocalSizeArrayIdx];
1898 assert(LocalSizeTy &&
"Local size type is expected");
1900 cast<ArrayType>(LocalSizeTy)->getNumElements();
1904 Int32Ty, MIRBuilder, SPIRV::StorageClass::Function);
1905 for (
unsigned I = 0;
I < LocalSizeNum; ++
I) {
1907 MRI->setType(
Reg, LLType);
1921 auto MIB = MIRBuilder.
buildInstr(SPIRV::OpEnqueueKernel)
1922 .
addDef(Call->ReturnRegister)
1926 const unsigned BlockFIdx = HasEvents ? 6 : 3;
1927 for (
unsigned i = 0; i < BlockFIdx; i++)
1928 MIB.addUse(Call->Arguments[i]);
1935 MIB.addUse(NullPtr);
1936 MIB.addUse(NullPtr);
1944 Register BlockLiteralReg = Call->Arguments[BlockFIdx + 1];
1946 MIB.addUse(BlockLiteralReg);
1956 for (
unsigned i = 0; i < LocalSizes.
size(); i++)
1957 MIB.addUse(LocalSizes[i]);
1967 SPIRV::lookupNativeBuiltin(Builtin->
Name, Builtin->
Set)->Opcode;
1970 case SPIRV::OpRetainEvent:
1971 case SPIRV::OpReleaseEvent:
1974 case SPIRV::OpCreateUserEvent:
1975 case SPIRV::OpGetDefaultQueue:
1977 .
addDef(Call->ReturnRegister)
1979 case SPIRV::OpIsValidEvent:
1982 .
addDef(Call->ReturnRegister)
1984 .
addUse(Call->Arguments[0]);
1985 case SPIRV::OpSetUserEventStatus:
1989 .
addUse(Call->Arguments[0])
1990 .
addUse(Call->Arguments[1]);
1991 case SPIRV::OpCaptureEventProfilingInfo:
1996 .
addUse(Call->Arguments[0])
1997 .
addUse(Call->Arguments[1])
1998 .
addUse(Call->Arguments[2]);
1999 case SPIRV::OpBuildNDRange:
2001 case SPIRV::OpEnqueueKernel:
2014 SPIRV::lookupNativeBuiltin(Builtin->
Name, Builtin->
Set)->Opcode;
2016 bool IsSet = Opcode == SPIRV::OpGroupAsyncCopy;
2018 if (Call->isSpirvOp())
2025 case SPIRV::OpGroupAsyncCopy:
2027 .
addDef(Call->ReturnRegister)
2030 .
addUse(Call->Arguments[0])
2031 .
addUse(Call->Arguments[1])
2032 .
addUse(Call->Arguments[2])
2034 .
addUse(Call->Arguments[3]);
2035 case SPIRV::OpGroupWaitEvents:
2038 .
addUse(Call->Arguments[0])
2039 .
addUse(Call->Arguments[1]);
2051 SPIRV::lookupConvertBuiltin(Call->Builtin->Name, Call->Builtin->Set);
2055 SPIRV::Decoration::SaturatedConversion, {});
2058 SPIRV::Decoration::FPRoundingMode,
2059 {(unsigned)Builtin->RoundingMode});
2061 std::string NeedExtMsg;
2062 bool IsRightComponentsNumber =
true;
2063 unsigned Opcode = SPIRV::OpNop;
2070 : SPIRV::OpSatConvertSToU;
2073 : SPIRV::OpSConvert;
2075 SPIRV::OpTypeFloat)) {
2080 if (!ST->canUseExtension(
2081 SPIRV::Extension::SPV_INTEL_bfloat16_conversion))
2082 NeedExtMsg =
"SPV_INTEL_bfloat16_conversion";
2083 IsRightComponentsNumber =
2086 Opcode = SPIRV::OpConvertBF16ToFINTEL;
2088 bool IsSourceSigned =
2090 Opcode = IsSourceSigned ? SPIRV::OpConvertSToF : SPIRV::OpConvertUToF;
2094 SPIRV::OpTypeFloat)) {
2101 if (!ST->canUseExtension(
2102 SPIRV::Extension::SPV_INTEL_bfloat16_conversion))
2103 NeedExtMsg =
"SPV_INTEL_bfloat16_conversion";
2104 IsRightComponentsNumber =
2107 Opcode = SPIRV::OpConvertFToBF16INTEL;
2110 : SPIRV::OpConvertFToU;
2113 SPIRV::OpTypeFloat)) {
2115 Opcode = SPIRV::OpFConvert;
2119 if (!NeedExtMsg.empty()) {
2120 std::string DiagMsg = std::string(Builtin->
Name) +
2121 ": the builtin requires the following SPIR-V "
2126 if (!IsRightComponentsNumber) {
2127 std::string DiagMsg =
2128 std::string(Builtin->
Name) +
2129 ": result and argument must have the same number of components";
2132 assert(Opcode != SPIRV::OpNop &&
2133 "Conversion between the types not implemented!");
2136 .
addDef(Call->ReturnRegister)
2138 .
addUse(Call->Arguments[0]);
2147 SPIRV::lookupVectorLoadStoreBuiltin(Call->Builtin->Name,
2148 Call->Builtin->Set);
2152 .
addDef(Call->ReturnRegister)
2154 .
addImm(
static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std))
2156 for (
auto Argument : Call->Arguments)
2174 SPIRV::lookupNativeBuiltin(Builtin->
Name, Builtin->
Set)->Opcode;
2175 bool IsLoad = Opcode == SPIRV::OpLoad;
2179 MIB.
addDef(Call->ReturnRegister);
2183 MIB.
addUse(Call->Arguments[0]);
2185 MRI->setRegClass(Call->Arguments[0], &SPIRV::IDRegClass);
2188 MIB.addUse(Call->Arguments[1]);
2189 MRI->setRegClass(Call->Arguments[1], &SPIRV::IDRegClass);
2192 unsigned NumArgs = Call->Arguments.size();
2193 if ((IsLoad && NumArgs >= 2) || NumArgs >= 3) {
2195 MRI->setRegClass(Call->Arguments[IsLoad ? 1 : 2], &SPIRV::IDRegClass);
2197 if ((IsLoad && NumArgs >= 3) || NumArgs >= 4) {
2199 MRI->setRegClass(Call->Arguments[IsLoad ? 2 : 3], &SPIRV::IDRegClass);
2208 SPIRV::InstructionSet::InstructionSet Set,
2213 LLVM_DEBUG(
dbgs() <<
"Lowering builtin call: " << DemangledCall <<
"\n");
2218 if (OrigRetTy && !OrigRetTy->
isVoidTy()) {
2222 }
else if (OrigRetTy && OrigRetTy->
isVoidTy()) {
2229 std::unique_ptr<const IncomingCall> Call =
2230 lookupBuiltin(DemangledCall, Set, ReturnRegister, ReturnType, Args);
2234 return std::nullopt;
2238 assert(Args.size() >= Call->Builtin->MinNumArgs &&
2239 "Too few arguments to generate the builtin");
2240 if (Call->Builtin->MaxNumArgs && Args.size() > Call->Builtin->MaxNumArgs)
2241 LLVM_DEBUG(
dbgs() <<
"More arguments provided than required!\n");
2244 switch (Call->Builtin->Group) {
2245 case SPIRV::Extended:
2247 case SPIRV::Relational:
2251 case SPIRV::Variable:
2255 case SPIRV::AtomicFloating:
2257 case SPIRV::Barrier:
2263 case SPIRV::GetQuery:
2265 case SPIRV::ImageSizeQuery:
2267 case SPIRV::ImageMiscQuery:
2269 case SPIRV::ReadImage:
2271 case SPIRV::WriteImage:
2273 case SPIRV::SampleImage:
2277 case SPIRV::SpecConstant:
2279 case SPIRV::Enqueue:
2281 case SPIRV::AsyncCopy:
2283 case SPIRV::Convert:
2285 case SPIRV::VectorLoadStore:
2287 case SPIRV::LoadStore:
2289 case SPIRV::IntelSubgroups:
2291 case SPIRV::GroupUniform:
2301 DemangledCall.
slice(DemangledCall.
find(
'(') + 1, DemangledCall.
find(
')'));
2302 BuiltinArgs.
split(BuiltinArgsTypeStrs,
',', -1,
false);
2303 if (ArgIdx >= BuiltinArgsTypeStrs.
size())
2305 StringRef TypeStr = BuiltinArgsTypeStrs[ArgIdx].trim();
2312 assert(IsOCLBuiltinType &&
"Invalid OpenCL builtin prefix");
2329 unsigned VecElts = 0;
2343 TypeStr = TypeStr.
substr(0, TypeStr.
find(
']'));
2357#define GET_BuiltinTypes_DECL
2358#define GET_BuiltinTypes_IMPL
2365#define GET_OpenCLTypes_DECL
2366#define GET_OpenCLTypes_IMPL
2368#include "SPIRVGenTables.inc"
2376 if (
Name.starts_with(
"void"))
2378 else if (
Name.starts_with(
"int") ||
Name.starts_with(
"uint"))
2380 else if (
Name.starts_with(
"float"))
2382 else if (
Name.starts_with(
"half"))
2395 unsigned Opcode = TypeRecord->
Opcode;
2410 "Invalid number of parameters for SPIR-V pipe builtin!");
2413 SPIRV::AccessQualifier::AccessQualifier(
2419 const SPIRV::AccessQualifier::AccessQualifier Qualifier,
2422 "SPIR-V image builtin type must have sampled type parameter!");
2426 "Invalid number of parameters for SPIR-V image builtin!");
2429 MIRBuilder, SampledType,
2434 Qualifier == SPIRV::AccessQualifier::WriteOnly
2435 ? SPIRV::AccessQualifier::WriteOnly
2436 : SPIRV::AccessQualifier::AccessQualifier(
2444 OpaqueType, SPIRV::AccessQualifier::ReadOnly, MIRBuilder, GR);
2452 StringRef NameWithParameters = TypeName;
2459 SPIRV::lookupOpenCLType(NameWithParameters);
2462 NameWithParameters);
2470 "Unknown builtin opaque type!");
2474 if (!NameWithParameters.
contains(
'_'))
2478 unsigned BaseNameLength = NameWithParameters.
find(
'_') - 1;
2479 SplitString(NameWithParameters.
substr(BaseNameLength + 1), Parameters,
"_");
2482 bool HasTypeParameter = !
isDigit(Parameters[0][0]);
2483 if (HasTypeParameter)
2486 for (
unsigned i = HasTypeParameter ? 1 : 0; i < Parameters.size(); i++) {
2487 unsigned IntParameter = 0;
2488 bool ValidLiteral = !Parameters[i].getAsInteger(10, IntParameter);
2491 "Invalid format of SPIR-V builtin parameter literal!");
2495 NameWithParameters.
substr(0, BaseNameLength),
2496 TypeParameters, IntParameters);
2500 SPIRV::AccessQualifier::AccessQualifier AccessQual,
2531 switch (TypeRecord->
Opcode) {
2532 case SPIRV::OpTypeImage:
2535 case SPIRV::OpTypePipe:
2538 case SPIRV::OpTypeDeviceEvent:
2541 case SPIRV::OpTypeSampler:
2544 case SPIRV::OpTypeSampledImage:
unsigned const MachineRegisterInfo * MRI
MachineInstrBuilder MachineInstrBuilder & DefMI
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
AMDGPU Lower Kernel Arguments
static bool isDigit(const char C)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
BaseType
A given derived pointer can have multiple base pointers through phi/selects.
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
APInt bitcastToAPInt() const
static APFloat getZero(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Zero.
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
uint64_t getZExtValue() const
Get zero extended value.
This class represents an incoming formal argument to a Function.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
static ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
@ ICMP_ULT
unsigned less than
const APFloat & getValueAPF() const
const APInt & getValue() const
Return the constant as an APInt value reference.
A parsed version of the target data layout string in and methods for querying it.
Tagged union holding either a T or a Error.
Class to represent fixed width SIMD vectors.
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
static IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
This is an important class for using LLVM in a threaded context.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
Helper class to build MachineInstr.
LLVMContext & getContext() const
MachineInstrBuilder buildSelect(const DstOp &Res, const SrcOp &Tst, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert a Res = G_SELECT Tst, Op0, Op1.
MachineInstrBuilder buildICmp(CmpInst::Predicate Pred, const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1)
Build and insert a Res = G_ICMP Pred, Op0, Op1.
MachineInstrBuilder buildIntrinsic(Intrinsic::ID ID, ArrayRef< Register > Res, bool HasSideEffects, bool isConvergent)
Build and insert a G_INTRINSIC instruction.
MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
MachineInstrBuilder buildZExtOrTrunc(const DstOp &Res, const SrcOp &Op)
Build and insert Res = G_ZEXT Op, Res = G_TRUNC Op, or Res = COPY Op depending on the differing sizes...
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
const DataLayout & getDataLayout() const
const MachineInstrBuilder & addImm(int64_t Val) const
Add a new immediate operand.
const MachineInstrBuilder & addUse(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
const MachineOperand & getOperand(unsigned i) const
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
const ConstantInt * getCImm() const
bool isCImm() const
isCImm - Test if this is a MO_CImmediate operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
const MDNode * getMetadata() const
Register getReg() const
getReg - Returns the register number.
const ConstantFP * getFPImm() const
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
void setType(Register VReg, LLT Ty)
Set the low-level type of VReg to Ty.
void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
const TargetRegisterClass * getRegClassOrNull(Register Reg) const
Return the register class of Reg, or null if Reg has not been assigned a register class yet.
unsigned getNumVirtRegs() const
getNumVirtRegs - Return the number of virtual registers created.
static PointerType * get(Type *ElementType, unsigned AddressSpace)
This constructs a pointer to an object of the specified type in a numbered address space.
Wrapper class representing virtual and physical registers.
constexpr bool isValid() const
SPIRVType * getOrCreateOpTypePipe(MachineIRBuilder &MIRBuilder, SPIRV::AccessQualifier::AccessQualifier AccQual)
SPIRVType * getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
SPIRVType * getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder)
Register getOrCreateConsIntVector(uint64_t Val, MachineIRBuilder &MIRBuilder, SPIRVType *SpvType, bool EmitIR=true)
const Type * getTypeForSPIRVType(const SPIRVType *Ty) const
Register buildConstantSampler(Register Res, unsigned AddrMode, unsigned Param, unsigned FilerMode, MachineIRBuilder &MIRBuilder, SPIRVType *SpvType)
unsigned getScalarOrVectorComponentCount(Register VReg) const
SPIRVType * getOrCreateOpTypeImage(MachineIRBuilder &MIRBuilder, SPIRVType *SampledType, SPIRV::Dim::Dim Dim, uint32_t Depth, uint32_t Arrayed, uint32_t Multisampled, uint32_t Sampled, SPIRV::ImageFormat::ImageFormat ImageFormat, SPIRV::AccessQualifier::AccessQualifier AccQual)
unsigned getPointerSize() const
SPIRVType * getOrCreateOpTypeByOpcode(const Type *Ty, MachineIRBuilder &MIRBuilder, unsigned Opcode)
Register buildConstantFP(APFloat Val, MachineIRBuilder &MIRBuilder, SPIRVType *SpvType=nullptr)
Register getSPIRVTypeID(const SPIRVType *SpirvType) const
SPIRVType * getOrCreateSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, SPIRV::AccessQualifier::AccessQualifier AQ=SPIRV::AccessQualifier::ReadWrite, bool EmitIR=true)
void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, MachineFunction &MF)
bool isScalarOfType(Register VReg, unsigned TypeOpcode) const
Register buildGlobalVariable(Register Reg, SPIRVType *BaseType, StringRef Name, const GlobalValue *GV, SPIRV::StorageClass::StorageClass Storage, const MachineInstr *Init, bool IsConst, bool HasLinkageTy, SPIRV::LinkageType::LinkageType LinkageType, MachineIRBuilder &MIRBuilder, bool IsInstSelector)
SPIRVType * getOrCreateOpTypeSampledImage(SPIRVType *ImageType, MachineIRBuilder &MIRBuilder)
SPIRVType * getOrCreateSPIRVTypeByName(StringRef TypeStr, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SC=SPIRV::StorageClass::Function, SPIRV::AccessQualifier::AccessQualifier AQ=SPIRV::AccessQualifier::ReadWrite)
SPIRVType * assignTypeToVReg(const Type *Type, Register VReg, MachineIRBuilder &MIRBuilder, SPIRV::AccessQualifier::AccessQualifier AQ=SPIRV::AccessQualifier::ReadWrite, bool EmitIR=true)
bool isScalarOrVectorOfType(Register VReg, unsigned TypeOpcode) const
SPIRVType * getOrCreateOpTypeDeviceEvent(MachineIRBuilder &MIRBuilder)
SPIRVType * getOrCreateSPIRVPointerType(SPIRVType *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SClass=SPIRV::StorageClass::Function)
SPIRVType * getOrCreateSPIRVVectorType(SPIRVType *BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder)
SPIRVType * getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineIRBuilder &MIRBuilder)
Register getOrCreateConsIntArray(uint64_t Val, MachineInstr &I, SPIRVType *SpvType, const SPIRVInstrInfo &TII)
SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const
SPIRVType * getOrCreateOpTypeSampler(MachineIRBuilder &MIRBuilder)
Register buildConstantInt(uint64_t Val, MachineIRBuilder &MIRBuilder, SPIRVType *SpvType=nullptr, bool EmitIR=true)
Register getOrCreateConstNullPtr(MachineIRBuilder &MIRBuilder, SPIRVType *SpvType)
unsigned getScalarOrVectorBitWidth(const SPIRVType *Type) const
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
bool consume_back(StringRef Suffix)
Returns true if this StringRef has the given suffix and removes that suffix.
bool getAsInteger(unsigned Radix, T &Result) const
Parse the current string as an integer of the specified radix.
std::string str() const
str - Get the contents as an std::string.
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
bool contains_insensitive(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
StringRef slice(size_t Start, size_t End) const
Return a reference to the substring from [Start, End).
bool contains(StringRef Other) const
Return true if the given string is a substring of *this, and false otherwise.
bool consume_front(StringRef Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
size_t find_first_of(char C, size_t From=0) const
Find the first character in the string that is C, or npos if not found.
size_t find(char C, size_t From=0) const
Search for the first character C in the string.
bool ends_with(StringRef Suffix) const
Check if this string ends with the given Suffix.
static constexpr size_t npos
Class to represent struct types.
static StructType * getTypeByName(LLVMContext &C, StringRef Name)
Return the type with the specified name, or null if there is none by that name.
static StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
Class to represent target extensions types, which are generally unintrospectable from target-independ...
unsigned getNumIntParameters() const
static TargetExtType * get(LLVMContext &Context, StringRef Name, ArrayRef< Type * > Types=std::nullopt, ArrayRef< unsigned > Ints=std::nullopt)
Return a target extension type having the specified name and optional type and integer parameters.
Type * getTypeParameter(unsigned i) const
unsigned getNumTypeParameters() const
unsigned getIntParameter(unsigned i) const
The instances of the Type class are immutable: once they are created, they are never changed.
static Type * getHalfTy(LLVMContext &C)
StringRef getStructName() const
static Type * getVoidTy(LLVMContext &C)
static IntegerType * getInt8Ty(LLVMContext &C)
static IntegerType * getInt32Ty(LLVMContext &C)
static Type * getFloatTy(LLVMContext &C)
bool isVoidTy() const
Return true if this is 'void'.
LLVM Value Representation.
Value(Type *Ty, unsigned scid)
static VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
NodeTy * getNextNode()
Get the next node, or nullptr for the list tail.
LLVMTypeRef LLVMVectorType(LLVMTypeRef ElementType, unsigned ElementCount)
Create a vector type that contains a defined type and has a specific number of elements.
Type * parseBuiltinCallArgumentBaseType(const StringRef DemangledCall, unsigned ArgIdx, LLVMContext &Ctx)
Parses the provided ArgIdx argument base type in the DemangledCall skeleton.
TargetExtType * parseBuiltinTypeNameToTargetExtType(std::string TypeName, LLVMContext &Context)
Translates a string representing a SPIR-V or OpenCL builtin type to a TargetExtType that can be furth...
std::optional< bool > lowerBuiltin(const StringRef DemangledCall, SPIRV::InstructionSet::InstructionSet Set, MachineIRBuilder &MIRBuilder, const Register OrigRet, const Type *OrigRetTy, const SmallVectorImpl< Register > &Args, SPIRVGlobalRegistry *GR)
SPIRVType * lowerBuiltinType(const Type *OpaqueType, SPIRV::AccessQualifier::AccessQualifier AccessQual, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
This is an optimization pass for GlobalISel generic memory operations.
void buildOpName(Register Target, const StringRef &Name, MachineIRBuilder &MIRBuilder)
unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC)
static bool generateGetQueryInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static bool generateLoadStoreInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static Register buildConstantIntReg(uint64_t Val, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR, unsigned BitWidth=32)
static bool buildAtomicFlagInst(const SPIRV::IncomingCall *Call, unsigned Opcode, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
Helper function for building atomic flag instructions (e.g.
static Register buildBuiltinVariableLoad(MachineIRBuilder &MIRBuilder, SPIRVType *VariableType, SPIRVGlobalRegistry *GR, SPIRV::BuiltIn::BuiltIn BuiltinValue, LLT LLType, Register Reg=Register(0), bool isConst=true, bool hasLinkageTy=true)
Helper function for building a load instruction for loading a builtin global variable of BuiltinValue...
static bool generateImageSizeQueryInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static SPIRV::SamplerFilterMode::SamplerFilterMode getSamplerFilterModeFromBitmask(unsigned Bitmask)
static bool buildAtomicStoreInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
Helper function for building an atomic store instruction.
void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB)
static const Type * getBlockStructType(Register ParamReg, MachineRegisterInfo *MRI)
static bool generateGroupInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static unsigned getNumComponentsForDim(SPIRV::Dim::Dim dim)
Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIB, MachineRegisterInfo &MRI)
Helper external function for inserting ASSIGN_TYPE instuction between Reg and its definition,...
static Register buildScopeReg(Register CLScopeRegister, SPIRV::Scope::Scope Scope, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI)
static std::tuple< Register, SPIRVType * > buildBoolRegister(MachineIRBuilder &MIRBuilder, const SPIRVType *ResultType, SPIRVGlobalRegistry *GR)
Helper function building either a resulting scalar or vector bool register depending on the expected ...
static unsigned getNumSizeComponents(SPIRVType *imgType)
Helper function for obtaining the number of size components.
uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI)
static SPIRVType * getSampledImageType(const TargetExtType *OpaqueType, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
SPIRV::MemorySemantics::MemorySemantics getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC)
static bool generateDotOrFMulInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static bool generateSampleImageInst(const StringRef DemangledCall, const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static bool generateBarrierInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static bool generateGroupUniformInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static bool generateWaveInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static SPIRVType * getImageType(const TargetExtType *ExtensionType, const SPIRV::AccessQualifier::AccessQualifier Qualifier, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, SPIRV::Decoration::Decoration Dec, const std::vector< uint32_t > &DecArgs, StringRef StrImm)
static bool buildBarrierInst(const SPIRV::IncomingCall *Call, unsigned Opcode, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
Helper function for building barriers, i.e., memory/control ordering operations.
static bool generateAsyncCopy(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static SPIRV::Scope::Scope getSPIRVScope(SPIRV::CLMemoryScope ClScope)
static SPIRVType * getSamplerType(MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
static Register buildLoadInst(SPIRVType *BaseType, Register PtrRegister, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR, LLT LowLevelType, Register DestinationReg=Register(0))
Helper function for building a load instruction loading into the DestinationReg.
static bool generateEnqueueInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
static bool buildSelectInst(MachineIRBuilder &MIRBuilder, Register ReturnRegister, Register SourceRegister, const SPIRVType *ReturnType, SPIRVGlobalRegistry *GR)
Helper function for building either a vector or scalar select instruction depending on the expected R...
static const Type * getMachineInstrType(MachineInstr *MI)
static SPIRV::SamplerAddressingMode::SamplerAddressingMode getSamplerAddressingModeFromBitmask(unsigned Bitmask)
static bool generateAtomicInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static bool generateConvertInst(const StringRef DemangledCall, const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static Register buildMemSemanticsReg(Register SemanticsRegister, Register PtrRegister, unsigned &Semantics, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static unsigned getConstFromIntrinsic(Register Reg, MachineRegisterInfo *MRI)
static bool generateImageMiscQueryInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static bool generateSelectInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder)
static bool buildAtomicLoadInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
Helper function for building an atomic load instruction.
static bool generateIntelSubgroupsInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static bool generateSpecConstantInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static SPIRVType * getOrCreateSPIRVDeviceEventPointer(MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
Type * parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx)
static bool generateVectorLoadStoreInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static bool genWorkgroupQuery(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR, SPIRV::BuiltIn::BuiltIn BuiltinValue, uint64_t DefaultValue)
static bool buildOpFromWrapper(MachineIRBuilder &MIRBuilder, unsigned Opcode, const SPIRV::IncomingCall *Call, Register TypeReg=Register(0))
static std::unique_ptr< const SPIRV::IncomingCall > lookupBuiltin(StringRef DemangledCall, SPIRV::InstructionSet::InstructionSet Set, Register ReturnRegister, const SPIRVType *ReturnType, const SmallVectorImpl< Register > &Arguments)
Looks up the demangled builtin call in the SPIRVBuiltins.td records using the provided DemangledCall ...
static bool buildAtomicFloatingRMWInst(const SPIRV::IncomingCall *Call, unsigned Opcode, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
Helper function for building an atomic floating-type instruction.
MachineInstr * getDefInstrMaybeConstant(Register &ConstReg, const MachineRegisterInfo *MRI)
constexpr unsigned BitWidth
const MachineInstr SPIRVType
static bool generateReadImageInst(const StringRef DemangledCall, const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
bool hasBuiltinTypePrefix(StringRef Name)
static bool buildEnqueueKernel(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
Type * getMDOperandAsType(const MDNode *N, unsigned I)
static bool buildAtomicRMWInst(const SPIRV::IncomingCall *Call, unsigned Opcode, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
Helper function for building an atomic load instruction.
static SPIRV::MemorySemantics::MemorySemantics getSPIRVMemSemantics(std::memory_order MemOrder)
static bool generateRelationalInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static bool buildAtomicInitInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder)
Helper function for translating atomic init to OpStore.
static bool generateWriteImageInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static SPIRVType * getPipeType(const TargetExtType *ExtensionType, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static Type * parseTypeString(const StringRef Name, LLVMContext &Context)
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID)
static bool generateAtomicFloatingInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static bool generateExtInst(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static bool buildNDRange(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static SPIRVType * getNonParameterizedType(const TargetExtType *ExtensionType, const SPIRV::BuiltinType *TypeRecord, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static MachineInstr * getBlockStructInstr(Register ParamReg, MachineRegisterInfo *MRI)
static unsigned getSamplerParamFromBitmask(unsigned Bitmask)
static bool buildAtomicCompareExchangeInst(const SPIRV::IncomingCall *Call, const SPIRV::DemangledBuiltin *Builtin, unsigned Opcode, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
Helper function for building an atomic compare-exchange instruction.
std::string getLinkStringForBuiltIn(SPIRV::BuiltIn::BuiltIn BuiltInValue)
static bool generateBuiltinVar(const SPIRV::IncomingCall *Call, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static const fltSemantics & IEEEsingle() LLVM_READNONE
This struct is a compact representation of a valid (non-zero power of two) alignment.
This class contains a discriminated union of information about pointers in memory operands,...
FPRoundingMode::FPRoundingMode RoundingMode
InstructionSet::InstructionSet Set
InstructionSet::InstructionSet Set
InstructionSet::InstructionSet Set
InstructionSet::InstructionSet Set
const SmallVectorImpl< Register > & Arguments
const std::string BuiltinName
const SPIRVType * ReturnType
const Register ReturnRegister
const DemangledBuiltin * Builtin
IncomingCall(const std::string BuiltinName, const DemangledBuiltin *Builtin, const Register ReturnRegister, const SPIRVType *ReturnType, const SmallVectorImpl< Register > &Arguments)
InstructionSet::InstructionSet Set
StringRef SpirvTypeLiteral
InstructionSet::InstructionSet Set
FPRoundingMode::FPRoundingMode RoundingMode