1f61eb416SIlia Diachkov //===- SPIRVBuiltins.cpp - SPIR-V Built-in Functions ------------*- C++ -*-===// 2f61eb416SIlia Diachkov // 3f61eb416SIlia Diachkov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4f61eb416SIlia Diachkov // See https://llvm.org/LICENSE.txt for license information. 5f61eb416SIlia Diachkov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f61eb416SIlia Diachkov // 7f61eb416SIlia Diachkov //===----------------------------------------------------------------------===// 8f61eb416SIlia Diachkov // 9f61eb416SIlia Diachkov // This file implements lowering builtin function calls and types using their 10f61eb416SIlia Diachkov // demangled names and TableGen records. 11f61eb416SIlia Diachkov // 12f61eb416SIlia Diachkov //===----------------------------------------------------------------------===// 13f61eb416SIlia Diachkov 14f61eb416SIlia Diachkov #include "SPIRVBuiltins.h" 15f61eb416SIlia Diachkov #include "SPIRV.h" 16b221b973SVyacheslav Levytskyy #include "SPIRVSubtarget.h" 17f61eb416SIlia Diachkov #include "SPIRVUtils.h" 18a48f32d2SFangrui Song #include "llvm/ADT/StringExtras.h" 19748922b3SIlia Diachkov #include "llvm/Analysis/ValueTracking.h" 20f61eb416SIlia Diachkov #include "llvm/IR/IntrinsicsSPIRV.h" 219b43078eSVyacheslav Levytskyy #include <regex> 22f61eb416SIlia Diachkov #include <string> 23f61eb416SIlia Diachkov #include <tuple> 24f61eb416SIlia Diachkov 25f61eb416SIlia Diachkov #define DEBUG_TYPE "spirv-builtins" 26f61eb416SIlia Diachkov 27f61eb416SIlia Diachkov namespace llvm { 28f61eb416SIlia Diachkov namespace SPIRV { 29f61eb416SIlia Diachkov #define GET_BuiltinGroup_DECL 30f61eb416SIlia Diachkov #include "SPIRVGenTables.inc" 31f61eb416SIlia Diachkov 32f61eb416SIlia Diachkov struct DemangledBuiltin { 33f61eb416SIlia Diachkov StringRef Name; 34f61eb416SIlia Diachkov InstructionSet::InstructionSet Set; 35f61eb416SIlia Diachkov BuiltinGroup Group; 36f61eb416SIlia Diachkov uint8_t MinNumArgs; 37f61eb416SIlia Diachkov uint8_t MaxNumArgs; 38f61eb416SIlia Diachkov }; 39f61eb416SIlia Diachkov 40f61eb416SIlia Diachkov #define GET_DemangledBuiltins_DECL 41f61eb416SIlia Diachkov #define GET_DemangledBuiltins_IMPL 42f61eb416SIlia Diachkov 43f61eb416SIlia Diachkov struct IncomingCall { 44f61eb416SIlia Diachkov const std::string BuiltinName; 45f61eb416SIlia Diachkov const DemangledBuiltin *Builtin; 46f61eb416SIlia Diachkov 47f61eb416SIlia Diachkov const Register ReturnRegister; 48f61eb416SIlia Diachkov const SPIRVType *ReturnType; 49f61eb416SIlia Diachkov const SmallVectorImpl<Register> &Arguments; 50f61eb416SIlia Diachkov 51f61eb416SIlia Diachkov IncomingCall(const std::string BuiltinName, const DemangledBuiltin *Builtin, 52f61eb416SIlia Diachkov const Register ReturnRegister, const SPIRVType *ReturnType, 53f61eb416SIlia Diachkov const SmallVectorImpl<Register> &Arguments) 54f61eb416SIlia Diachkov : BuiltinName(BuiltinName), Builtin(Builtin), 55f61eb416SIlia Diachkov ReturnRegister(ReturnRegister), ReturnType(ReturnType), 56f61eb416SIlia Diachkov Arguments(Arguments) {} 57c2483ed5SVyacheslav Levytskyy 58c2483ed5SVyacheslav Levytskyy bool isSpirvOp() const { return BuiltinName.rfind("__spirv_", 0) == 0; } 59f61eb416SIlia Diachkov }; 60f61eb416SIlia Diachkov 61f61eb416SIlia Diachkov struct NativeBuiltin { 62f61eb416SIlia Diachkov StringRef Name; 63f61eb416SIlia Diachkov InstructionSet::InstructionSet Set; 64f61eb416SIlia Diachkov uint32_t Opcode; 65f61eb416SIlia Diachkov }; 66f61eb416SIlia Diachkov 67f61eb416SIlia Diachkov #define GET_NativeBuiltins_DECL 68f61eb416SIlia Diachkov #define GET_NativeBuiltins_IMPL 69f61eb416SIlia Diachkov 70f61eb416SIlia Diachkov struct GroupBuiltin { 71f61eb416SIlia Diachkov StringRef Name; 72f61eb416SIlia Diachkov uint32_t Opcode; 73f61eb416SIlia Diachkov uint32_t GroupOperation; 74f61eb416SIlia Diachkov bool IsElect; 75f61eb416SIlia Diachkov bool IsAllOrAny; 76f61eb416SIlia Diachkov bool IsAllEqual; 77f61eb416SIlia Diachkov bool IsBallot; 78f61eb416SIlia Diachkov bool IsInverseBallot; 79f61eb416SIlia Diachkov bool IsBallotBitExtract; 80f61eb416SIlia Diachkov bool IsBallotFindBit; 81f61eb416SIlia Diachkov bool IsLogical; 82f61eb416SIlia Diachkov bool NoGroupOperation; 83f61eb416SIlia Diachkov bool HasBoolArg; 84f61eb416SIlia Diachkov }; 85f61eb416SIlia Diachkov 86f61eb416SIlia Diachkov #define GET_GroupBuiltins_DECL 87f61eb416SIlia Diachkov #define GET_GroupBuiltins_IMPL 88f61eb416SIlia Diachkov 89b221b973SVyacheslav Levytskyy struct IntelSubgroupsBuiltin { 90b221b973SVyacheslav Levytskyy StringRef Name; 91b221b973SVyacheslav Levytskyy uint32_t Opcode; 92b221b973SVyacheslav Levytskyy bool IsBlock; 93b221b973SVyacheslav Levytskyy bool IsWrite; 944a6ecd38SViktoria Maximova bool IsMedia; 95b221b973SVyacheslav Levytskyy }; 96b221b973SVyacheslav Levytskyy 97b221b973SVyacheslav Levytskyy #define GET_IntelSubgroupsBuiltins_DECL 98b221b973SVyacheslav Levytskyy #define GET_IntelSubgroupsBuiltins_IMPL 99b221b973SVyacheslav Levytskyy 100925768eeSVyacheslav Levytskyy struct AtomicFloatingBuiltin { 101925768eeSVyacheslav Levytskyy StringRef Name; 102925768eeSVyacheslav Levytskyy uint32_t Opcode; 103925768eeSVyacheslav Levytskyy }; 104925768eeSVyacheslav Levytskyy 105925768eeSVyacheslav Levytskyy #define GET_AtomicFloatingBuiltins_DECL 106925768eeSVyacheslav Levytskyy #define GET_AtomicFloatingBuiltins_IMPL 10766ebda46SVyacheslav Levytskyy struct GroupUniformBuiltin { 10866ebda46SVyacheslav Levytskyy StringRef Name; 10966ebda46SVyacheslav Levytskyy uint32_t Opcode; 11066ebda46SVyacheslav Levytskyy bool IsLogical; 11166ebda46SVyacheslav Levytskyy }; 11266ebda46SVyacheslav Levytskyy 11366ebda46SVyacheslav Levytskyy #define GET_GroupUniformBuiltins_DECL 11466ebda46SVyacheslav Levytskyy #define GET_GroupUniformBuiltins_IMPL 115925768eeSVyacheslav Levytskyy 116f61eb416SIlia Diachkov struct GetBuiltin { 117f61eb416SIlia Diachkov StringRef Name; 118f61eb416SIlia Diachkov InstructionSet::InstructionSet Set; 119f61eb416SIlia Diachkov BuiltIn::BuiltIn Value; 120f61eb416SIlia Diachkov }; 121f61eb416SIlia Diachkov 122f61eb416SIlia Diachkov using namespace BuiltIn; 123f61eb416SIlia Diachkov #define GET_GetBuiltins_DECL 124f61eb416SIlia Diachkov #define GET_GetBuiltins_IMPL 125f61eb416SIlia Diachkov 126f61eb416SIlia Diachkov struct ImageQueryBuiltin { 127f61eb416SIlia Diachkov StringRef Name; 128f61eb416SIlia Diachkov InstructionSet::InstructionSet Set; 129f61eb416SIlia Diachkov uint32_t Component; 130f61eb416SIlia Diachkov }; 131f61eb416SIlia Diachkov 132f61eb416SIlia Diachkov #define GET_ImageQueryBuiltins_DECL 133f61eb416SIlia Diachkov #define GET_ImageQueryBuiltins_IMPL 134f61eb416SIlia Diachkov 135f61eb416SIlia Diachkov struct ConvertBuiltin { 136f61eb416SIlia Diachkov StringRef Name; 137f61eb416SIlia Diachkov InstructionSet::InstructionSet Set; 138f61eb416SIlia Diachkov bool IsDestinationSigned; 139f61eb416SIlia Diachkov bool IsSaturated; 140f61eb416SIlia Diachkov bool IsRounded; 1418f30b623SVyacheslav Levytskyy bool IsBfloat16; 142f61eb416SIlia Diachkov FPRoundingMode::FPRoundingMode RoundingMode; 143f61eb416SIlia Diachkov }; 144f61eb416SIlia Diachkov 145f61eb416SIlia Diachkov struct VectorLoadStoreBuiltin { 146f61eb416SIlia Diachkov StringRef Name; 147f61eb416SIlia Diachkov InstructionSet::InstructionSet Set; 148f61eb416SIlia Diachkov uint32_t Number; 14903203b79SMichal Paszkowski uint32_t ElementCount; 150f61eb416SIlia Diachkov bool IsRounded; 151f61eb416SIlia Diachkov FPRoundingMode::FPRoundingMode RoundingMode; 152f61eb416SIlia Diachkov }; 153f61eb416SIlia Diachkov 154f61eb416SIlia Diachkov using namespace FPRoundingMode; 155f61eb416SIlia Diachkov #define GET_ConvertBuiltins_DECL 156f61eb416SIlia Diachkov #define GET_ConvertBuiltins_IMPL 157f61eb416SIlia Diachkov 158f61eb416SIlia Diachkov using namespace InstructionSet; 159f61eb416SIlia Diachkov #define GET_VectorLoadStoreBuiltins_DECL 160f61eb416SIlia Diachkov #define GET_VectorLoadStoreBuiltins_IMPL 161f61eb416SIlia Diachkov 162f61eb416SIlia Diachkov #define GET_CLMemoryScope_DECL 163f61eb416SIlia Diachkov #define GET_CLSamplerAddressingMode_DECL 164f61eb416SIlia Diachkov #define GET_CLMemoryFenceFlags_DECL 165f61eb416SIlia Diachkov #define GET_ExtendedBuiltins_DECL 166f61eb416SIlia Diachkov #include "SPIRVGenTables.inc" 167f61eb416SIlia Diachkov } // namespace SPIRV 168f61eb416SIlia Diachkov 169f61eb416SIlia Diachkov //===----------------------------------------------------------------------===// 170f61eb416SIlia Diachkov // Misc functions for looking up builtins and veryfying requirements using 171f61eb416SIlia Diachkov // TableGen records 172f61eb416SIlia Diachkov //===----------------------------------------------------------------------===// 173f61eb416SIlia Diachkov 174dbd00a59SVyacheslav Levytskyy namespace SPIRV { 175dbd00a59SVyacheslav Levytskyy /// Parses the name part of the demangled builtin call. 176978de2d6SVyacheslav Levytskyy std::string lookupBuiltinNameHelper(StringRef DemangledCall, 1773ed2a813SVyacheslav Levytskyy FPDecorationId *DecorationId) { 178bf9e9e5eSVyacheslav Levytskyy const static std::string PassPrefix = "(anonymous namespace)::"; 179bf9e9e5eSVyacheslav Levytskyy std::string BuiltinName; 180bf9e9e5eSVyacheslav Levytskyy // Itanium Demangler result may have "(anonymous namespace)::" prefix 181bf9e9e5eSVyacheslav Levytskyy if (DemangledCall.starts_with(PassPrefix.c_str())) 182bf9e9e5eSVyacheslav Levytskyy BuiltinName = DemangledCall.substr(PassPrefix.length()); 183bf9e9e5eSVyacheslav Levytskyy else 184bf9e9e5eSVyacheslav Levytskyy BuiltinName = DemangledCall; 185f61eb416SIlia Diachkov // Extract the builtin function name and types of arguments from the call 186f61eb416SIlia Diachkov // skeleton. 187bf9e9e5eSVyacheslav Levytskyy BuiltinName = BuiltinName.substr(0, BuiltinName.find('(')); 188f61eb416SIlia Diachkov 1891ed1ec9aSVyacheslav Levytskyy // Account for possible "__spirv_ocl_" prefix in SPIR-V friendly LLVM IR 1901ed1ec9aSVyacheslav Levytskyy if (BuiltinName.rfind("__spirv_ocl_", 0) == 0) 1911ed1ec9aSVyacheslav Levytskyy BuiltinName = BuiltinName.substr(12); 1921ed1ec9aSVyacheslav Levytskyy 193f61eb416SIlia Diachkov // Check if the extracted name contains type information between angle 194f61eb416SIlia Diachkov // brackets. If so, the builtin is an instantiated template - needs to have 195f61eb416SIlia Diachkov // the information after angle brackets and return type removed. 1968ac46d6bSVyacheslav Levytskyy std::size_t Pos1 = BuiltinName.rfind('<'); 1978ac46d6bSVyacheslav Levytskyy if (Pos1 != std::string::npos && BuiltinName.back() == '>') { 1988ac46d6bSVyacheslav Levytskyy std::size_t Pos2 = BuiltinName.rfind(' ', Pos1); 1998ac46d6bSVyacheslav Levytskyy if (Pos2 == std::string::npos) 2008ac46d6bSVyacheslav Levytskyy Pos2 = 0; 2018ac46d6bSVyacheslav Levytskyy else 2028ac46d6bSVyacheslav Levytskyy ++Pos2; 2038ac46d6bSVyacheslav Levytskyy BuiltinName = BuiltinName.substr(Pos2, Pos1 - Pos2); 20433b51588Sserge-sans-paille BuiltinName = BuiltinName.substr(BuiltinName.find_last_of(' ') + 1); 205f61eb416SIlia Diachkov } 206f61eb416SIlia Diachkov 2079b43078eSVyacheslav Levytskyy // Check if the extracted name begins with: 2089b43078eSVyacheslav Levytskyy // - "__spirv_ImageSampleExplicitLod" 2099b43078eSVyacheslav Levytskyy // - "__spirv_ImageRead" 2109b43078eSVyacheslav Levytskyy // - "__spirv_ImageQuerySizeLod" 2119b43078eSVyacheslav Levytskyy // - "__spirv_UDotKHR" 2129b43078eSVyacheslav Levytskyy // - "__spirv_SDotKHR" 2139b43078eSVyacheslav Levytskyy // - "__spirv_SUDotKHR" 2149b43078eSVyacheslav Levytskyy // - "__spirv_SDotAccSatKHR" 2159b43078eSVyacheslav Levytskyy // - "__spirv_UDotAccSatKHR" 2169b43078eSVyacheslav Levytskyy // - "__spirv_SUDotAccSatKHR" 2179b43078eSVyacheslav Levytskyy // - "__spirv_ReadClockKHR" 2189b43078eSVyacheslav Levytskyy // - "__spirv_SubgroupBlockReadINTEL" 2199b43078eSVyacheslav Levytskyy // - "__spirv_SubgroupImageBlockReadINTEL" 2204a6ecd38SViktoria Maximova // - "__spirv_SubgroupImageMediaBlockReadINTEL" 2214a6ecd38SViktoria Maximova // - "__spirv_SubgroupImageMediaBlockWriteINTEL" 2229b43078eSVyacheslav Levytskyy // - "__spirv_Convert" 2239b43078eSVyacheslav Levytskyy // - "__spirv_UConvert" 2249b43078eSVyacheslav Levytskyy // - "__spirv_SConvert" 2259b43078eSVyacheslav Levytskyy // - "__spirv_FConvert" 2269b43078eSVyacheslav Levytskyy // - "__spirv_SatConvert" 2279b43078eSVyacheslav Levytskyy // and contains return type information at the end "_R<type>". 2289b43078eSVyacheslav Levytskyy // If so, extract the plain builtin name without the type information. 2299b43078eSVyacheslav Levytskyy static const std::regex SpvWithR( 2309b43078eSVyacheslav Levytskyy "(__spirv_(ImageSampleExplicitLod|ImageRead|ImageQuerySizeLod|UDotKHR|" 2319b43078eSVyacheslav Levytskyy "SDotKHR|SUDotKHR|SDotAccSatKHR|UDotAccSatKHR|SUDotAccSatKHR|" 2324a6ecd38SViktoria Maximova "ReadClockKHR|SubgroupBlockReadINTEL|SubgroupImageBlockReadINTEL|" 2334a6ecd38SViktoria Maximova "SubgroupImageMediaBlockReadINTEL|SubgroupImageMediaBlockWriteINTEL|" 2344a6ecd38SViktoria Maximova "Convert|" 2353ed2a813SVyacheslav Levytskyy "UConvert|SConvert|FConvert|SatConvert).*)_R[^_]*_?(\\w+)?.*"); 2369b43078eSVyacheslav Levytskyy std::smatch Match; 2373ed2a813SVyacheslav Levytskyy if (std::regex_match(BuiltinName, Match, SpvWithR) && Match.size() > 1) { 2383ed2a813SVyacheslav Levytskyy std::ssub_match SubMatch; 2393ed2a813SVyacheslav Levytskyy if (DecorationId && Match.size() > 3) { 2403ed2a813SVyacheslav Levytskyy SubMatch = Match[3]; 2413ed2a813SVyacheslav Levytskyy *DecorationId = demangledPostfixToDecorationId(SubMatch.str()); 2423ed2a813SVyacheslav Levytskyy } 2433ed2a813SVyacheslav Levytskyy SubMatch = Match[1]; 2443ed2a813SVyacheslav Levytskyy BuiltinName = SubMatch.str(); 245978de2d6SVyacheslav Levytskyy } 246f61eb416SIlia Diachkov 247dbd00a59SVyacheslav Levytskyy return BuiltinName; 248dbd00a59SVyacheslav Levytskyy } 249dbd00a59SVyacheslav Levytskyy } // namespace SPIRV 250dbd00a59SVyacheslav Levytskyy 251dbd00a59SVyacheslav Levytskyy /// Looks up the demangled builtin call in the SPIRVBuiltins.td records using 252dbd00a59SVyacheslav Levytskyy /// the provided \p DemangledCall and specified \p Set. 253dbd00a59SVyacheslav Levytskyy /// 254dbd00a59SVyacheslav Levytskyy /// The lookup follows the following algorithm, returning the first successful 255dbd00a59SVyacheslav Levytskyy /// match: 256dbd00a59SVyacheslav Levytskyy /// 1. Search with the plain demangled name (expecting a 1:1 match). 257dbd00a59SVyacheslav Levytskyy /// 2. Search with the prefix before or suffix after the demangled name 258dbd00a59SVyacheslav Levytskyy /// signyfying the type of the first argument. 259dbd00a59SVyacheslav Levytskyy /// 260dbd00a59SVyacheslav Levytskyy /// \returns Wrapper around the demangled call and found builtin definition. 261dbd00a59SVyacheslav Levytskyy static std::unique_ptr<const SPIRV::IncomingCall> 262dbd00a59SVyacheslav Levytskyy lookupBuiltin(StringRef DemangledCall, 263dbd00a59SVyacheslav Levytskyy SPIRV::InstructionSet::InstructionSet Set, 264dbd00a59SVyacheslav Levytskyy Register ReturnRegister, const SPIRVType *ReturnType, 265dbd00a59SVyacheslav Levytskyy const SmallVectorImpl<Register> &Arguments) { 266dbd00a59SVyacheslav Levytskyy std::string BuiltinName = SPIRV::lookupBuiltinNameHelper(DemangledCall); 267dbd00a59SVyacheslav Levytskyy 268f61eb416SIlia Diachkov SmallVector<StringRef, 10> BuiltinArgumentTypes; 269f61eb416SIlia Diachkov StringRef BuiltinArgs = 270f61eb416SIlia Diachkov DemangledCall.slice(DemangledCall.find('(') + 1, DemangledCall.find(')')); 271f61eb416SIlia Diachkov BuiltinArgs.split(BuiltinArgumentTypes, ',', -1, false); 272f61eb416SIlia Diachkov 273f61eb416SIlia Diachkov // Look up the builtin in the defined set. Start with the plain demangled 274f61eb416SIlia Diachkov // name, expecting a 1:1 match in the defined builtin set. 275f61eb416SIlia Diachkov const SPIRV::DemangledBuiltin *Builtin; 276f61eb416SIlia Diachkov if ((Builtin = SPIRV::lookupBuiltin(BuiltinName, Set))) 277f61eb416SIlia Diachkov return std::make_unique<SPIRV::IncomingCall>( 278f61eb416SIlia Diachkov BuiltinName, Builtin, ReturnRegister, ReturnType, Arguments); 279f61eb416SIlia Diachkov 280f61eb416SIlia Diachkov // If the initial look up was unsuccessful and the demangled call takes at 281f61eb416SIlia Diachkov // least 1 argument, add a prefix or suffix signifying the type of the first 282f61eb416SIlia Diachkov // argument and repeat the search. 283f61eb416SIlia Diachkov if (BuiltinArgumentTypes.size() >= 1) { 284f61eb416SIlia Diachkov char FirstArgumentType = BuiltinArgumentTypes[0][0]; 285f61eb416SIlia Diachkov // Prefix to be added to the builtin's name for lookup. 286f61eb416SIlia Diachkov // For example, OpenCL "abs" taking an unsigned value has a prefix "u_". 287f61eb416SIlia Diachkov std::string Prefix; 288f61eb416SIlia Diachkov 289f61eb416SIlia Diachkov switch (FirstArgumentType) { 290f61eb416SIlia Diachkov // Unsigned: 291f61eb416SIlia Diachkov case 'u': 292f61eb416SIlia Diachkov if (Set == SPIRV::InstructionSet::OpenCL_std) 293f61eb416SIlia Diachkov Prefix = "u_"; 294f61eb416SIlia Diachkov else if (Set == SPIRV::InstructionSet::GLSL_std_450) 295f61eb416SIlia Diachkov Prefix = "u"; 296f61eb416SIlia Diachkov break; 297f61eb416SIlia Diachkov // Signed: 298f61eb416SIlia Diachkov case 'c': 299f61eb416SIlia Diachkov case 's': 300f61eb416SIlia Diachkov case 'i': 301f61eb416SIlia Diachkov case 'l': 302f61eb416SIlia Diachkov if (Set == SPIRV::InstructionSet::OpenCL_std) 303f61eb416SIlia Diachkov Prefix = "s_"; 304f61eb416SIlia Diachkov else if (Set == SPIRV::InstructionSet::GLSL_std_450) 305f61eb416SIlia Diachkov Prefix = "s"; 306f61eb416SIlia Diachkov break; 307f61eb416SIlia Diachkov // Floating-point: 308f61eb416SIlia Diachkov case 'f': 309f61eb416SIlia Diachkov case 'd': 310f61eb416SIlia Diachkov case 'h': 311f61eb416SIlia Diachkov if (Set == SPIRV::InstructionSet::OpenCL_std || 312f61eb416SIlia Diachkov Set == SPIRV::InstructionSet::GLSL_std_450) 313f61eb416SIlia Diachkov Prefix = "f"; 314f61eb416SIlia Diachkov break; 315f61eb416SIlia Diachkov } 316f61eb416SIlia Diachkov 317f61eb416SIlia Diachkov // If argument-type name prefix was added, look up the builtin again. 318f61eb416SIlia Diachkov if (!Prefix.empty() && 319f61eb416SIlia Diachkov (Builtin = SPIRV::lookupBuiltin(Prefix + BuiltinName, Set))) 320f61eb416SIlia Diachkov return std::make_unique<SPIRV::IncomingCall>( 321f61eb416SIlia Diachkov BuiltinName, Builtin, ReturnRegister, ReturnType, Arguments); 322f61eb416SIlia Diachkov 323f61eb416SIlia Diachkov // If lookup with a prefix failed, find a suffix to be added to the 324f61eb416SIlia Diachkov // builtin's name for lookup. For example, OpenCL "group_reduce_max" taking 325f61eb416SIlia Diachkov // an unsigned value has a suffix "u". 326f61eb416SIlia Diachkov std::string Suffix; 327f61eb416SIlia Diachkov 328f61eb416SIlia Diachkov switch (FirstArgumentType) { 329f61eb416SIlia Diachkov // Unsigned: 330f61eb416SIlia Diachkov case 'u': 331f61eb416SIlia Diachkov Suffix = "u"; 332f61eb416SIlia Diachkov break; 333f61eb416SIlia Diachkov // Signed: 334f61eb416SIlia Diachkov case 'c': 335f61eb416SIlia Diachkov case 's': 336f61eb416SIlia Diachkov case 'i': 337f61eb416SIlia Diachkov case 'l': 338f61eb416SIlia Diachkov Suffix = "s"; 339f61eb416SIlia Diachkov break; 340f61eb416SIlia Diachkov // Floating-point: 341f61eb416SIlia Diachkov case 'f': 342f61eb416SIlia Diachkov case 'd': 343f61eb416SIlia Diachkov case 'h': 344f61eb416SIlia Diachkov Suffix = "f"; 345f61eb416SIlia Diachkov break; 346f61eb416SIlia Diachkov } 347f61eb416SIlia Diachkov 348f61eb416SIlia Diachkov // If argument-type name suffix was added, look up the builtin again. 349f61eb416SIlia Diachkov if (!Suffix.empty() && 350f61eb416SIlia Diachkov (Builtin = SPIRV::lookupBuiltin(BuiltinName + Suffix, Set))) 351f61eb416SIlia Diachkov return std::make_unique<SPIRV::IncomingCall>( 352f61eb416SIlia Diachkov BuiltinName, Builtin, ReturnRegister, ReturnType, Arguments); 353f61eb416SIlia Diachkov } 354f61eb416SIlia Diachkov 355f61eb416SIlia Diachkov // No builtin with such name was found in the set. 356f61eb416SIlia Diachkov return nullptr; 357f61eb416SIlia Diachkov } 358f61eb416SIlia Diachkov 35957520985SVyacheslav Levytskyy static MachineInstr *getBlockStructInstr(Register ParamReg, 36057520985SVyacheslav Levytskyy MachineRegisterInfo *MRI) { 36157520985SVyacheslav Levytskyy // We expect the following sequence of instructions: 36257520985SVyacheslav Levytskyy // %0:_(pN) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.spv.alloca) 36357520985SVyacheslav Levytskyy // or = G_GLOBAL_VALUE @block_literal_global 36457520985SVyacheslav Levytskyy // %1:_(pN) = G_INTRINSIC_W_SIDE_EFFECTS intrinsic(@llvm.spv.bitcast), %0 36557520985SVyacheslav Levytskyy // %2:_(p4) = G_ADDRSPACE_CAST %1:_(pN) 36657520985SVyacheslav Levytskyy MachineInstr *MI = MRI->getUniqueVRegDef(ParamReg); 36757520985SVyacheslav Levytskyy assert(MI->getOpcode() == TargetOpcode::G_ADDRSPACE_CAST && 36857520985SVyacheslav Levytskyy MI->getOperand(1).isReg()); 36957520985SVyacheslav Levytskyy Register BitcastReg = MI->getOperand(1).getReg(); 37057520985SVyacheslav Levytskyy MachineInstr *BitcastMI = MRI->getUniqueVRegDef(BitcastReg); 37157520985SVyacheslav Levytskyy assert(isSpvIntrinsic(*BitcastMI, Intrinsic::spv_bitcast) && 37257520985SVyacheslav Levytskyy BitcastMI->getOperand(2).isReg()); 37357520985SVyacheslav Levytskyy Register ValueReg = BitcastMI->getOperand(2).getReg(); 37457520985SVyacheslav Levytskyy MachineInstr *ValueMI = MRI->getUniqueVRegDef(ValueReg); 37557520985SVyacheslav Levytskyy return ValueMI; 37657520985SVyacheslav Levytskyy } 37757520985SVyacheslav Levytskyy 37857520985SVyacheslav Levytskyy // Return an integer constant corresponding to the given register and 37957520985SVyacheslav Levytskyy // defined in spv_track_constant. 38057520985SVyacheslav Levytskyy // TODO: maybe unify with prelegalizer pass. 38157520985SVyacheslav Levytskyy static unsigned getConstFromIntrinsic(Register Reg, MachineRegisterInfo *MRI) { 38257520985SVyacheslav Levytskyy MachineInstr *DefMI = MRI->getUniqueVRegDef(Reg); 38357520985SVyacheslav Levytskyy assert(isSpvIntrinsic(*DefMI, Intrinsic::spv_track_constant) && 38457520985SVyacheslav Levytskyy DefMI->getOperand(2).isReg()); 38557520985SVyacheslav Levytskyy MachineInstr *DefMI2 = MRI->getUniqueVRegDef(DefMI->getOperand(2).getReg()); 38657520985SVyacheslav Levytskyy assert(DefMI2->getOpcode() == TargetOpcode::G_CONSTANT && 38757520985SVyacheslav Levytskyy DefMI2->getOperand(1).isCImm()); 38857520985SVyacheslav Levytskyy return DefMI2->getOperand(1).getCImm()->getValue().getZExtValue(); 38957520985SVyacheslav Levytskyy } 39057520985SVyacheslav Levytskyy 39157520985SVyacheslav Levytskyy // Return type of the instruction result from spv_assign_type intrinsic. 39257520985SVyacheslav Levytskyy // TODO: maybe unify with prelegalizer pass. 39357520985SVyacheslav Levytskyy static const Type *getMachineInstrType(MachineInstr *MI) { 39457520985SVyacheslav Levytskyy MachineInstr *NextMI = MI->getNextNode(); 39557520985SVyacheslav Levytskyy if (!NextMI) 39657520985SVyacheslav Levytskyy return nullptr; 39757520985SVyacheslav Levytskyy if (isSpvIntrinsic(*NextMI, Intrinsic::spv_assign_name)) 39857520985SVyacheslav Levytskyy if ((NextMI = NextMI->getNextNode()) == nullptr) 39957520985SVyacheslav Levytskyy return nullptr; 40057520985SVyacheslav Levytskyy Register ValueReg = MI->getOperand(0).getReg(); 40157520985SVyacheslav Levytskyy if ((!isSpvIntrinsic(*NextMI, Intrinsic::spv_assign_type) && 40257520985SVyacheslav Levytskyy !isSpvIntrinsic(*NextMI, Intrinsic::spv_assign_ptr_type)) || 40357520985SVyacheslav Levytskyy NextMI->getOperand(1).getReg() != ValueReg) 40457520985SVyacheslav Levytskyy return nullptr; 40557520985SVyacheslav Levytskyy Type *Ty = getMDOperandAsType(NextMI->getOperand(2).getMetadata(), 0); 40657520985SVyacheslav Levytskyy assert(Ty && "Type is expected"); 40757520985SVyacheslav Levytskyy return Ty; 40857520985SVyacheslav Levytskyy } 40957520985SVyacheslav Levytskyy 41057520985SVyacheslav Levytskyy static const Type *getBlockStructType(Register ParamReg, 41157520985SVyacheslav Levytskyy MachineRegisterInfo *MRI) { 41257520985SVyacheslav Levytskyy // In principle, this information should be passed to us from Clang via 41357520985SVyacheslav Levytskyy // an elementtype attribute. However, said attribute requires that 41457520985SVyacheslav Levytskyy // the function call be an intrinsic, which is not. Instead, we rely on being 41557520985SVyacheslav Levytskyy // able to trace this to the declaration of a variable: OpenCL C specification 41657520985SVyacheslav Levytskyy // section 6.12.5 should guarantee that we can do this. 41757520985SVyacheslav Levytskyy MachineInstr *MI = getBlockStructInstr(ParamReg, MRI); 41857520985SVyacheslav Levytskyy if (MI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE) 41957520985SVyacheslav Levytskyy return MI->getOperand(1).getGlobal()->getType(); 42057520985SVyacheslav Levytskyy assert(isSpvIntrinsic(*MI, Intrinsic::spv_alloca) && 42157520985SVyacheslav Levytskyy "Blocks in OpenCL C must be traceable to allocation site"); 42257520985SVyacheslav Levytskyy return getMachineInstrType(MI); 42357520985SVyacheslav Levytskyy } 42457520985SVyacheslav Levytskyy 425f61eb416SIlia Diachkov //===----------------------------------------------------------------------===// 426f61eb416SIlia Diachkov // Helper functions for building misc instructions 427f61eb416SIlia Diachkov //===----------------------------------------------------------------------===// 428f61eb416SIlia Diachkov 429f61eb416SIlia Diachkov /// Helper function building either a resulting scalar or vector bool register 430f61eb416SIlia Diachkov /// depending on the expected \p ResultType. 431f61eb416SIlia Diachkov /// 432f61eb416SIlia Diachkov /// \returns Tuple of the resulting register and its type. 433f61eb416SIlia Diachkov static std::tuple<Register, SPIRVType *> 434f61eb416SIlia Diachkov buildBoolRegister(MachineIRBuilder &MIRBuilder, const SPIRVType *ResultType, 435f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 436f61eb416SIlia Diachkov LLT Type; 437f61eb416SIlia Diachkov SPIRVType *BoolType = GR->getOrCreateSPIRVBoolType(MIRBuilder); 438f61eb416SIlia Diachkov 439f61eb416SIlia Diachkov if (ResultType->getOpcode() == SPIRV::OpTypeVector) { 440f61eb416SIlia Diachkov unsigned VectorElements = ResultType->getOperand(2).getImm(); 441f61eb416SIlia Diachkov BoolType = 442f61eb416SIlia Diachkov GR->getOrCreateSPIRVVectorType(BoolType, VectorElements, MIRBuilder); 443f61eb416SIlia Diachkov const FixedVectorType *LLVMVectorType = 444f61eb416SIlia Diachkov cast<FixedVectorType>(GR->getTypeForSPIRVType(BoolType)); 445f61eb416SIlia Diachkov Type = LLT::vector(LLVMVectorType->getElementCount(), 1); 446f61eb416SIlia Diachkov } else { 447f61eb416SIlia Diachkov Type = LLT::scalar(1); 448f61eb416SIlia Diachkov } 449f61eb416SIlia Diachkov 450f61eb416SIlia Diachkov Register ResultRegister = 451f61eb416SIlia Diachkov MIRBuilder.getMRI()->createGenericVirtualRegister(Type); 45267d3ef74SVyacheslav Levytskyy MIRBuilder.getMRI()->setRegClass(ResultRegister, GR->getRegClass(ResultType)); 453f61eb416SIlia Diachkov GR->assignSPIRVTypeToVReg(BoolType, ResultRegister, MIRBuilder.getMF()); 454f61eb416SIlia Diachkov return std::make_tuple(ResultRegister, BoolType); 455f61eb416SIlia Diachkov } 456f61eb416SIlia Diachkov 457f61eb416SIlia Diachkov /// Helper function for building either a vector or scalar select instruction 458f61eb416SIlia Diachkov /// depending on the expected \p ResultType. 459f61eb416SIlia Diachkov static bool buildSelectInst(MachineIRBuilder &MIRBuilder, 460f61eb416SIlia Diachkov Register ReturnRegister, Register SourceRegister, 461f61eb416SIlia Diachkov const SPIRVType *ReturnType, 462f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 463f61eb416SIlia Diachkov Register TrueConst, FalseConst; 464f61eb416SIlia Diachkov 465f61eb416SIlia Diachkov if (ReturnType->getOpcode() == SPIRV::OpTypeVector) { 466f61eb416SIlia Diachkov unsigned Bits = GR->getScalarOrVectorBitWidth(ReturnType); 467147ff1b4SMichal Paszkowski uint64_t AllOnes = APInt::getAllOnes(Bits).getZExtValue(); 468f61eb416SIlia Diachkov TrueConst = GR->getOrCreateConsIntVector(AllOnes, MIRBuilder, ReturnType); 469f61eb416SIlia Diachkov FalseConst = GR->getOrCreateConsIntVector(0, MIRBuilder, ReturnType); 470f61eb416SIlia Diachkov } else { 471f61eb416SIlia Diachkov TrueConst = GR->buildConstantInt(1, MIRBuilder, ReturnType); 472f61eb416SIlia Diachkov FalseConst = GR->buildConstantInt(0, MIRBuilder, ReturnType); 473f61eb416SIlia Diachkov } 47467d3ef74SVyacheslav Levytskyy 475f61eb416SIlia Diachkov return MIRBuilder.buildSelect(ReturnRegister, SourceRegister, TrueConst, 476f61eb416SIlia Diachkov FalseConst); 477f61eb416SIlia Diachkov } 478f61eb416SIlia Diachkov 479f61eb416SIlia Diachkov /// Helper function for building a load instruction loading into the 480f61eb416SIlia Diachkov /// \p DestinationReg. 481f61eb416SIlia Diachkov static Register buildLoadInst(SPIRVType *BaseType, Register PtrRegister, 482f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 483f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR, LLT LowLevelType, 484f61eb416SIlia Diachkov Register DestinationReg = Register(0)) { 485b5132b7dSVyacheslav Levytskyy if (!DestinationReg.isValid()) 486b5132b7dSVyacheslav Levytskyy DestinationReg = createVirtualRegister(BaseType, GR, MIRBuilder); 487f61eb416SIlia Diachkov // TODO: consider using correct address space and alignment (p0 is canonical 488f61eb416SIlia Diachkov // type for selection though). 489f61eb416SIlia Diachkov MachinePointerInfo PtrInfo = MachinePointerInfo(); 490f61eb416SIlia Diachkov MIRBuilder.buildLoad(DestinationReg, PtrRegister, PtrInfo, Align()); 491f61eb416SIlia Diachkov return DestinationReg; 492f61eb416SIlia Diachkov } 493f61eb416SIlia Diachkov 494f61eb416SIlia Diachkov /// Helper function for building a load instruction for loading a builtin global 495f61eb416SIlia Diachkov /// variable of \p BuiltinValue value. 496f0eb9083SNathan Gauër static Register buildBuiltinVariableLoad( 497f0eb9083SNathan Gauër MachineIRBuilder &MIRBuilder, SPIRVType *VariableType, 498f0eb9083SNathan Gauër SPIRVGlobalRegistry *GR, SPIRV::BuiltIn::BuiltIn BuiltinValue, LLT LLType, 499f0eb9083SNathan Gauër Register Reg = Register(0), bool isConst = true, bool hasLinkageTy = true) { 500f61eb416SIlia Diachkov Register NewRegister = 5018ac46d6bSVyacheslav Levytskyy MIRBuilder.getMRI()->createVirtualRegister(&SPIRV::pIDRegClass); 5028ac46d6bSVyacheslav Levytskyy MIRBuilder.getMRI()->setType( 5038ac46d6bSVyacheslav Levytskyy NewRegister, 5048ac46d6bSVyacheslav Levytskyy LLT::pointer(storageClassToAddressSpace(SPIRV::StorageClass::Function), 5058ac46d6bSVyacheslav Levytskyy GR->getPointerSize())); 506f61eb416SIlia Diachkov SPIRVType *PtrType = GR->getOrCreateSPIRVPointerType( 507f61eb416SIlia Diachkov VariableType, MIRBuilder, SPIRV::StorageClass::Input); 508f61eb416SIlia Diachkov GR->assignSPIRVTypeToVReg(PtrType, NewRegister, MIRBuilder.getMF()); 509f61eb416SIlia Diachkov 510f61eb416SIlia Diachkov // Set up the global OpVariable with the necessary builtin decorations. 511f61eb416SIlia Diachkov Register Variable = GR->buildGlobalVariable( 512f61eb416SIlia Diachkov NewRegister, PtrType, getLinkStringForBuiltIn(BuiltinValue), nullptr, 513f0eb9083SNathan Gauër SPIRV::StorageClass::Input, nullptr, /* isConst= */ isConst, 514f0eb9083SNathan Gauër /* HasLinkageTy */ hasLinkageTy, SPIRV::LinkageType::Import, MIRBuilder, 515f0eb9083SNathan Gauër false); 516f61eb416SIlia Diachkov 517f61eb416SIlia Diachkov // Load the value from the global variable. 518f61eb416SIlia Diachkov Register LoadedRegister = 519f61eb416SIlia Diachkov buildLoadInst(VariableType, Variable, MIRBuilder, GR, LLType, Reg); 520f61eb416SIlia Diachkov MIRBuilder.getMRI()->setType(LoadedRegister, LLType); 521f61eb416SIlia Diachkov return LoadedRegister; 522f61eb416SIlia Diachkov } 523f61eb416SIlia Diachkov 524f61eb416SIlia Diachkov /// Helper external function for inserting ASSIGN_TYPE instuction between \p Reg 525f61eb416SIlia Diachkov /// and its definition, set the new register as a destination of the definition, 526f61eb416SIlia Diachkov /// assign SPIRVType to both registers. If SpirvTy is provided, use it as 527f61eb416SIlia Diachkov /// SPIRVType in ASSIGN_TYPE, otherwise create it from \p Ty. Defined in 528f61eb416SIlia Diachkov /// SPIRVPreLegalizer.cpp. 529f61eb416SIlia Diachkov extern Register insertAssignInstr(Register Reg, Type *Ty, SPIRVType *SpirvTy, 530f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR, 531f61eb416SIlia Diachkov MachineIRBuilder &MIB, 532f61eb416SIlia Diachkov MachineRegisterInfo &MRI); 533f61eb416SIlia Diachkov 534f61eb416SIlia Diachkov // TODO: Move to TableGen. 535f61eb416SIlia Diachkov static SPIRV::MemorySemantics::MemorySemantics 536f61eb416SIlia Diachkov getSPIRVMemSemantics(std::memory_order MemOrder) { 537f61eb416SIlia Diachkov switch (MemOrder) { 538fe7cb156SVyacheslav Levytskyy case std::memory_order_relaxed: 539f61eb416SIlia Diachkov return SPIRV::MemorySemantics::None; 540fe7cb156SVyacheslav Levytskyy case std::memory_order_acquire: 541f61eb416SIlia Diachkov return SPIRV::MemorySemantics::Acquire; 542fe7cb156SVyacheslav Levytskyy case std::memory_order_release: 543f61eb416SIlia Diachkov return SPIRV::MemorySemantics::Release; 544fe7cb156SVyacheslav Levytskyy case std::memory_order_acq_rel: 545f61eb416SIlia Diachkov return SPIRV::MemorySemantics::AcquireRelease; 546fe7cb156SVyacheslav Levytskyy case std::memory_order_seq_cst: 547f61eb416SIlia Diachkov return SPIRV::MemorySemantics::SequentiallyConsistent; 548f61eb416SIlia Diachkov default: 549925768eeSVyacheslav Levytskyy report_fatal_error("Unknown CL memory scope"); 550f61eb416SIlia Diachkov } 551f61eb416SIlia Diachkov } 552f61eb416SIlia Diachkov 553f61eb416SIlia Diachkov static SPIRV::Scope::Scope getSPIRVScope(SPIRV::CLMemoryScope ClScope) { 554f61eb416SIlia Diachkov switch (ClScope) { 555f61eb416SIlia Diachkov case SPIRV::CLMemoryScope::memory_scope_work_item: 556f61eb416SIlia Diachkov return SPIRV::Scope::Invocation; 557f61eb416SIlia Diachkov case SPIRV::CLMemoryScope::memory_scope_work_group: 558f61eb416SIlia Diachkov return SPIRV::Scope::Workgroup; 559f61eb416SIlia Diachkov case SPIRV::CLMemoryScope::memory_scope_device: 560f61eb416SIlia Diachkov return SPIRV::Scope::Device; 561f61eb416SIlia Diachkov case SPIRV::CLMemoryScope::memory_scope_all_svm_devices: 562f61eb416SIlia Diachkov return SPIRV::Scope::CrossDevice; 563f61eb416SIlia Diachkov case SPIRV::CLMemoryScope::memory_scope_sub_group: 564f61eb416SIlia Diachkov return SPIRV::Scope::Subgroup; 565f61eb416SIlia Diachkov } 566925768eeSVyacheslav Levytskyy report_fatal_error("Unknown CL memory scope"); 567f61eb416SIlia Diachkov } 568f61eb416SIlia Diachkov 56967d3ef74SVyacheslav Levytskyy static Register buildConstantIntReg32(uint64_t Val, 57067d3ef74SVyacheslav Levytskyy MachineIRBuilder &MIRBuilder, 57167d3ef74SVyacheslav Levytskyy SPIRVGlobalRegistry *GR) { 57267d3ef74SVyacheslav Levytskyy return GR->buildConstantInt(Val, MIRBuilder, 57367d3ef74SVyacheslav Levytskyy GR->getOrCreateSPIRVIntegerType(32, MIRBuilder)); 574f61eb416SIlia Diachkov } 575f61eb416SIlia Diachkov 57687080898SMichal Paszkowski static Register buildScopeReg(Register CLScopeRegister, 57774c66710SIlia Diachkov SPIRV::Scope::Scope Scope, 57887080898SMichal Paszkowski MachineIRBuilder &MIRBuilder, 57987080898SMichal Paszkowski SPIRVGlobalRegistry *GR, 58074c66710SIlia Diachkov MachineRegisterInfo *MRI) { 58174c66710SIlia Diachkov if (CLScopeRegister.isValid()) { 58287080898SMichal Paszkowski auto CLScope = 58387080898SMichal Paszkowski static_cast<SPIRV::CLMemoryScope>(getIConstVal(CLScopeRegister, MRI)); 58474c66710SIlia Diachkov Scope = getSPIRVScope(CLScope); 58587080898SMichal Paszkowski 58674c66710SIlia Diachkov if (CLScope == static_cast<unsigned>(Scope)) { 587f9c98068SVyacheslav Levytskyy MRI->setRegClass(CLScopeRegister, &SPIRV::iIDRegClass); 58887080898SMichal Paszkowski return CLScopeRegister; 58974c66710SIlia Diachkov } 59074c66710SIlia Diachkov } 59167d3ef74SVyacheslav Levytskyy return buildConstantIntReg32(Scope, MIRBuilder, GR); 59287080898SMichal Paszkowski } 59387080898SMichal Paszkowski 594978de2d6SVyacheslav Levytskyy static void setRegClassIfNull(Register Reg, MachineRegisterInfo *MRI, 595978de2d6SVyacheslav Levytskyy SPIRVGlobalRegistry *GR) { 596978de2d6SVyacheslav Levytskyy if (MRI->getRegClassOrNull(Reg)) 597978de2d6SVyacheslav Levytskyy return; 598978de2d6SVyacheslav Levytskyy SPIRVType *SpvType = GR->getSPIRVTypeForVReg(Reg); 599978de2d6SVyacheslav Levytskyy MRI->setRegClass(Reg, 600978de2d6SVyacheslav Levytskyy SpvType ? GR->getRegClass(SpvType) : &SPIRV::iIDRegClass); 601978de2d6SVyacheslav Levytskyy } 602978de2d6SVyacheslav Levytskyy 60387080898SMichal Paszkowski static Register buildMemSemanticsReg(Register SemanticsRegister, 60474c66710SIlia Diachkov Register PtrRegister, unsigned &Semantics, 60574c66710SIlia Diachkov MachineIRBuilder &MIRBuilder, 60687080898SMichal Paszkowski SPIRVGlobalRegistry *GR) { 60774c66710SIlia Diachkov if (SemanticsRegister.isValid()) { 60874c66710SIlia Diachkov MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 60987080898SMichal Paszkowski std::memory_order Order = 61087080898SMichal Paszkowski static_cast<std::memory_order>(getIConstVal(SemanticsRegister, MRI)); 61174c66710SIlia Diachkov Semantics = 61287080898SMichal Paszkowski getSPIRVMemSemantics(Order) | 61387080898SMichal Paszkowski getMemSemanticsForStorageClass(GR->getPointerStorageClass(PtrRegister)); 614b45072d9SMichal Paszkowski if (static_cast<unsigned>(Order) == Semantics) { 615f9c98068SVyacheslav Levytskyy MRI->setRegClass(SemanticsRegister, &SPIRV::iIDRegClass); 61687080898SMichal Paszkowski return SemanticsRegister; 61774c66710SIlia Diachkov } 61874c66710SIlia Diachkov } 61967d3ef74SVyacheslav Levytskyy return buildConstantIntReg32(Semantics, MIRBuilder, GR); 62087080898SMichal Paszkowski } 62187080898SMichal Paszkowski 622c2483ed5SVyacheslav Levytskyy static bool buildOpFromWrapper(MachineIRBuilder &MIRBuilder, unsigned Opcode, 623c2483ed5SVyacheslav Levytskyy const SPIRV::IncomingCall *Call, 62457f79371SVyacheslav Levytskyy Register TypeReg, 62557f79371SVyacheslav Levytskyy ArrayRef<uint32_t> ImmArgs = {}) { 626c2483ed5SVyacheslav Levytskyy auto MIB = MIRBuilder.buildInstr(Opcode); 627c2483ed5SVyacheslav Levytskyy if (TypeReg.isValid()) 628c2483ed5SVyacheslav Levytskyy MIB.addDef(Call->ReturnRegister).addUse(TypeReg); 62957f79371SVyacheslav Levytskyy unsigned Sz = Call->Arguments.size() - ImmArgs.size(); 63067d3ef74SVyacheslav Levytskyy for (unsigned i = 0; i < Sz; ++i) 63167d3ef74SVyacheslav Levytskyy MIB.addUse(Call->Arguments[i]); 63257f79371SVyacheslav Levytskyy for (uint32_t ImmArg : ImmArgs) 63357f79371SVyacheslav Levytskyy MIB.addImm(ImmArg); 634c2483ed5SVyacheslav Levytskyy return true; 635c2483ed5SVyacheslav Levytskyy } 636c2483ed5SVyacheslav Levytskyy 6375fb4a051SMichal Paszkowski /// Helper function for translating atomic init to OpStore. 6385fb4a051SMichal Paszkowski static bool buildAtomicInitInst(const SPIRV::IncomingCall *Call, 6395fb4a051SMichal Paszkowski MachineIRBuilder &MIRBuilder) { 640c2483ed5SVyacheslav Levytskyy if (Call->isSpirvOp()) 64157f79371SVyacheslav Levytskyy return buildOpFromWrapper(MIRBuilder, SPIRV::OpStore, Call, Register(0)); 642c2483ed5SVyacheslav Levytskyy 6435fb4a051SMichal Paszkowski assert(Call->Arguments.size() == 2 && 6445fb4a051SMichal Paszkowski "Need 2 arguments for atomic init translation"); 6455fb4a051SMichal Paszkowski MIRBuilder.buildInstr(SPIRV::OpStore) 6465fb4a051SMichal Paszkowski .addUse(Call->Arguments[0]) 6475fb4a051SMichal Paszkowski .addUse(Call->Arguments[1]); 6485fb4a051SMichal Paszkowski return true; 6495fb4a051SMichal Paszkowski } 6505fb4a051SMichal Paszkowski 651f61eb416SIlia Diachkov /// Helper function for building an atomic load instruction. 652f61eb416SIlia Diachkov static bool buildAtomicLoadInst(const SPIRV::IncomingCall *Call, 653f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 654f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 655c2483ed5SVyacheslav Levytskyy Register TypeReg = GR->getSPIRVTypeID(Call->ReturnType); 656c2483ed5SVyacheslav Levytskyy if (Call->isSpirvOp()) 657c2483ed5SVyacheslav Levytskyy return buildOpFromWrapper(MIRBuilder, SPIRV::OpAtomicLoad, Call, TypeReg); 658c2483ed5SVyacheslav Levytskyy 659f61eb416SIlia Diachkov Register PtrRegister = Call->Arguments[0]; 660f61eb416SIlia Diachkov // TODO: if true insert call to __translate_ocl_memory_sccope before 661f61eb416SIlia Diachkov // OpAtomicLoad and the function implementation. We can use Translator's 662f61eb416SIlia Diachkov // output for transcoding/atomic_explicit_arguments.cl as an example. 66367d3ef74SVyacheslav Levytskyy Register ScopeRegister = 66467d3ef74SVyacheslav Levytskyy Call->Arguments.size() > 1 66567d3ef74SVyacheslav Levytskyy ? Call->Arguments[1] 66667d3ef74SVyacheslav Levytskyy : buildConstantIntReg32(SPIRV::Scope::Device, MIRBuilder, GR); 667f61eb416SIlia Diachkov Register MemSemanticsReg; 668f61eb416SIlia Diachkov if (Call->Arguments.size() > 2) { 669f61eb416SIlia Diachkov // TODO: Insert call to __translate_ocl_memory_order before OpAtomicLoad. 670f61eb416SIlia Diachkov MemSemanticsReg = Call->Arguments[2]; 671f61eb416SIlia Diachkov } else { 672f61eb416SIlia Diachkov int Semantics = 673f61eb416SIlia Diachkov SPIRV::MemorySemantics::SequentiallyConsistent | 674f61eb416SIlia Diachkov getMemSemanticsForStorageClass(GR->getPointerStorageClass(PtrRegister)); 67567d3ef74SVyacheslav Levytskyy MemSemanticsReg = buildConstantIntReg32(Semantics, MIRBuilder, GR); 676f61eb416SIlia Diachkov } 677f61eb416SIlia Diachkov 678f61eb416SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpAtomicLoad) 679f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 680c2483ed5SVyacheslav Levytskyy .addUse(TypeReg) 681f61eb416SIlia Diachkov .addUse(PtrRegister) 682f61eb416SIlia Diachkov .addUse(ScopeRegister) 683f61eb416SIlia Diachkov .addUse(MemSemanticsReg); 684f61eb416SIlia Diachkov return true; 685f61eb416SIlia Diachkov } 686f61eb416SIlia Diachkov 687f61eb416SIlia Diachkov /// Helper function for building an atomic store instruction. 688f61eb416SIlia Diachkov static bool buildAtomicStoreInst(const SPIRV::IncomingCall *Call, 689f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 690f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 691c2483ed5SVyacheslav Levytskyy if (Call->isSpirvOp()) 69257f79371SVyacheslav Levytskyy return buildOpFromWrapper(MIRBuilder, SPIRV::OpAtomicStore, Call, Register(0)); 693c2483ed5SVyacheslav Levytskyy 694f61eb416SIlia Diachkov Register ScopeRegister = 69567d3ef74SVyacheslav Levytskyy buildConstantIntReg32(SPIRV::Scope::Device, MIRBuilder, GR); 696f61eb416SIlia Diachkov Register PtrRegister = Call->Arguments[0]; 697f61eb416SIlia Diachkov int Semantics = 698f61eb416SIlia Diachkov SPIRV::MemorySemantics::SequentiallyConsistent | 699f61eb416SIlia Diachkov getMemSemanticsForStorageClass(GR->getPointerStorageClass(PtrRegister)); 70067d3ef74SVyacheslav Levytskyy Register MemSemanticsReg = buildConstantIntReg32(Semantics, MIRBuilder, GR); 701f61eb416SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpAtomicStore) 702f61eb416SIlia Diachkov .addUse(PtrRegister) 703f61eb416SIlia Diachkov .addUse(ScopeRegister) 704f61eb416SIlia Diachkov .addUse(MemSemanticsReg) 705f61eb416SIlia Diachkov .addUse(Call->Arguments[1]); 706f61eb416SIlia Diachkov return true; 707f61eb416SIlia Diachkov } 708f61eb416SIlia Diachkov 709f61eb416SIlia Diachkov /// Helper function for building an atomic compare-exchange instruction. 710c2483ed5SVyacheslav Levytskyy static bool buildAtomicCompareExchangeInst( 711c2483ed5SVyacheslav Levytskyy const SPIRV::IncomingCall *Call, const SPIRV::DemangledBuiltin *Builtin, 712c2483ed5SVyacheslav Levytskyy unsigned Opcode, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR) { 713c2483ed5SVyacheslav Levytskyy if (Call->isSpirvOp()) 714c2483ed5SVyacheslav Levytskyy return buildOpFromWrapper(MIRBuilder, Opcode, Call, 715c2483ed5SVyacheslav Levytskyy GR->getSPIRVTypeID(Call->ReturnType)); 716c2483ed5SVyacheslav Levytskyy 717f61eb416SIlia Diachkov bool IsCmpxchg = Call->Builtin->Name.contains("cmpxchg"); 718f61eb416SIlia Diachkov MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 719f61eb416SIlia Diachkov 720f61eb416SIlia Diachkov Register ObjectPtr = Call->Arguments[0]; // Pointer (volatile A *object.) 721f61eb416SIlia Diachkov Register ExpectedArg = Call->Arguments[1]; // Comparator (C* expected). 722f61eb416SIlia Diachkov Register Desired = Call->Arguments[2]; // Value (C Desired). 723f61eb416SIlia Diachkov SPIRVType *SpvDesiredTy = GR->getSPIRVTypeForVReg(Desired); 724f61eb416SIlia Diachkov LLT DesiredLLT = MRI->getType(Desired); 725f61eb416SIlia Diachkov 726f61eb416SIlia Diachkov assert(GR->getSPIRVTypeForVReg(ObjectPtr)->getOpcode() == 727f61eb416SIlia Diachkov SPIRV::OpTypePointer); 728f61eb416SIlia Diachkov unsigned ExpectedType = GR->getSPIRVTypeForVReg(ExpectedArg)->getOpcode(); 729b221b973SVyacheslav Levytskyy (void)ExpectedType; 730f61eb416SIlia Diachkov assert(IsCmpxchg ? ExpectedType == SPIRV::OpTypeInt 731f61eb416SIlia Diachkov : ExpectedType == SPIRV::OpTypePointer); 732f61eb416SIlia Diachkov assert(GR->isScalarOfType(Desired, SPIRV::OpTypeInt)); 733f61eb416SIlia Diachkov 734f61eb416SIlia Diachkov SPIRVType *SpvObjectPtrTy = GR->getSPIRVTypeForVReg(ObjectPtr); 735f61eb416SIlia Diachkov assert(SpvObjectPtrTy->getOperand(2).isReg() && "SPIRV type is expected"); 736f61eb416SIlia Diachkov auto StorageClass = static_cast<SPIRV::StorageClass::StorageClass>( 737f61eb416SIlia Diachkov SpvObjectPtrTy->getOperand(1).getImm()); 738f61eb416SIlia Diachkov auto MemSemStorage = getMemSemanticsForStorageClass(StorageClass); 739f61eb416SIlia Diachkov 740f61eb416SIlia Diachkov Register MemSemEqualReg; 741f61eb416SIlia Diachkov Register MemSemUnequalReg; 742f61eb416SIlia Diachkov uint64_t MemSemEqual = 743f61eb416SIlia Diachkov IsCmpxchg 744f61eb416SIlia Diachkov ? SPIRV::MemorySemantics::None 745f61eb416SIlia Diachkov : SPIRV::MemorySemantics::SequentiallyConsistent | MemSemStorage; 746f61eb416SIlia Diachkov uint64_t MemSemUnequal = 747f61eb416SIlia Diachkov IsCmpxchg 748f61eb416SIlia Diachkov ? SPIRV::MemorySemantics::None 749f61eb416SIlia Diachkov : SPIRV::MemorySemantics::SequentiallyConsistent | MemSemStorage; 750f61eb416SIlia Diachkov if (Call->Arguments.size() >= 4) { 751f61eb416SIlia Diachkov assert(Call->Arguments.size() >= 5 && 752f61eb416SIlia Diachkov "Need 5+ args for explicit atomic cmpxchg"); 753f61eb416SIlia Diachkov auto MemOrdEq = 754f61eb416SIlia Diachkov static_cast<std::memory_order>(getIConstVal(Call->Arguments[3], MRI)); 755f61eb416SIlia Diachkov auto MemOrdNeq = 756f61eb416SIlia Diachkov static_cast<std::memory_order>(getIConstVal(Call->Arguments[4], MRI)); 757f61eb416SIlia Diachkov MemSemEqual = getSPIRVMemSemantics(MemOrdEq) | MemSemStorage; 758f61eb416SIlia Diachkov MemSemUnequal = getSPIRVMemSemantics(MemOrdNeq) | MemSemStorage; 759b45072d9SMichal Paszkowski if (static_cast<unsigned>(MemOrdEq) == MemSemEqual) 760f61eb416SIlia Diachkov MemSemEqualReg = Call->Arguments[3]; 761b45072d9SMichal Paszkowski if (static_cast<unsigned>(MemOrdNeq) == MemSemEqual) 762f61eb416SIlia Diachkov MemSemUnequalReg = Call->Arguments[4]; 763f61eb416SIlia Diachkov } 764f61eb416SIlia Diachkov if (!MemSemEqualReg.isValid()) 76567d3ef74SVyacheslav Levytskyy MemSemEqualReg = buildConstantIntReg32(MemSemEqual, MIRBuilder, GR); 766f61eb416SIlia Diachkov if (!MemSemUnequalReg.isValid()) 76767d3ef74SVyacheslav Levytskyy MemSemUnequalReg = buildConstantIntReg32(MemSemUnequal, MIRBuilder, GR); 768f61eb416SIlia Diachkov 769f61eb416SIlia Diachkov Register ScopeReg; 770f61eb416SIlia Diachkov auto Scope = IsCmpxchg ? SPIRV::Scope::Workgroup : SPIRV::Scope::Device; 771f61eb416SIlia Diachkov if (Call->Arguments.size() >= 6) { 772f61eb416SIlia Diachkov assert(Call->Arguments.size() == 6 && 773f61eb416SIlia Diachkov "Extra args for explicit atomic cmpxchg"); 774f61eb416SIlia Diachkov auto ClScope = static_cast<SPIRV::CLMemoryScope>( 775f61eb416SIlia Diachkov getIConstVal(Call->Arguments[5], MRI)); 776f61eb416SIlia Diachkov Scope = getSPIRVScope(ClScope); 777f61eb416SIlia Diachkov if (ClScope == static_cast<unsigned>(Scope)) 778f61eb416SIlia Diachkov ScopeReg = Call->Arguments[5]; 779f61eb416SIlia Diachkov } 780f61eb416SIlia Diachkov if (!ScopeReg.isValid()) 78167d3ef74SVyacheslav Levytskyy ScopeReg = buildConstantIntReg32(Scope, MIRBuilder, GR); 782f61eb416SIlia Diachkov 783f61eb416SIlia Diachkov Register Expected = IsCmpxchg 784f61eb416SIlia Diachkov ? ExpectedArg 785f61eb416SIlia Diachkov : buildLoadInst(SpvDesiredTy, ExpectedArg, MIRBuilder, 78667d3ef74SVyacheslav Levytskyy GR, LLT::scalar(64)); 787f61eb416SIlia Diachkov MRI->setType(Expected, DesiredLLT); 788f61eb416SIlia Diachkov Register Tmp = !IsCmpxchg ? MRI->createGenericVirtualRegister(DesiredLLT) 789f61eb416SIlia Diachkov : Call->ReturnRegister; 79074c66710SIlia Diachkov if (!MRI->getRegClassOrNull(Tmp)) 79167d3ef74SVyacheslav Levytskyy MRI->setRegClass(Tmp, GR->getRegClass(SpvDesiredTy)); 792f61eb416SIlia Diachkov GR->assignSPIRVTypeToVReg(SpvDesiredTy, Tmp, MIRBuilder.getMF()); 793f61eb416SIlia Diachkov 794f61eb416SIlia Diachkov SPIRVType *IntTy = GR->getOrCreateSPIRVIntegerType(32, MIRBuilder); 795f61eb416SIlia Diachkov MIRBuilder.buildInstr(Opcode) 796f61eb416SIlia Diachkov .addDef(Tmp) 797f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(IntTy)) 798f61eb416SIlia Diachkov .addUse(ObjectPtr) 799f61eb416SIlia Diachkov .addUse(ScopeReg) 800f61eb416SIlia Diachkov .addUse(MemSemEqualReg) 801f61eb416SIlia Diachkov .addUse(MemSemUnequalReg) 802f61eb416SIlia Diachkov .addUse(Desired) 803f61eb416SIlia Diachkov .addUse(Expected); 804f61eb416SIlia Diachkov if (!IsCmpxchg) { 805f61eb416SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpStore).addUse(ExpectedArg).addUse(Tmp); 806f61eb416SIlia Diachkov MIRBuilder.buildICmp(CmpInst::ICMP_EQ, Call->ReturnRegister, Tmp, Expected); 807f61eb416SIlia Diachkov } 808f61eb416SIlia Diachkov return true; 809f61eb416SIlia Diachkov } 810f61eb416SIlia Diachkov 811378630b4SVyacheslav Levytskyy /// Helper function for building atomic instructions. 812f61eb416SIlia Diachkov static bool buildAtomicRMWInst(const SPIRV::IncomingCall *Call, unsigned Opcode, 813f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 814f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 815c2483ed5SVyacheslav Levytskyy if (Call->isSpirvOp()) 816c2483ed5SVyacheslav Levytskyy return buildOpFromWrapper(MIRBuilder, Opcode, Call, 817c2483ed5SVyacheslav Levytskyy GR->getSPIRVTypeID(Call->ReturnType)); 818c2483ed5SVyacheslav Levytskyy 81974c66710SIlia Diachkov MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 82074c66710SIlia Diachkov Register ScopeRegister = 82174c66710SIlia Diachkov Call->Arguments.size() >= 4 ? Call->Arguments[3] : Register(); 82287080898SMichal Paszkowski 82374c66710SIlia Diachkov assert(Call->Arguments.size() <= 4 && 82487080898SMichal Paszkowski "Too many args for explicit atomic RMW"); 82574c66710SIlia Diachkov ScopeRegister = buildScopeReg(ScopeRegister, SPIRV::Scope::Workgroup, 82674c66710SIlia Diachkov MIRBuilder, GR, MRI); 827f61eb416SIlia Diachkov 828f61eb416SIlia Diachkov Register PtrRegister = Call->Arguments[0]; 829f61eb416SIlia Diachkov unsigned Semantics = SPIRV::MemorySemantics::None; 83074c66710SIlia Diachkov Register MemSemanticsReg = 83174c66710SIlia Diachkov Call->Arguments.size() >= 3 ? Call->Arguments[2] : Register(); 83274c66710SIlia Diachkov MemSemanticsReg = buildMemSemanticsReg(MemSemanticsReg, PtrRegister, 83374c66710SIlia Diachkov Semantics, MIRBuilder, GR); 834378630b4SVyacheslav Levytskyy Register ValueReg = Call->Arguments[1]; 835378630b4SVyacheslav Levytskyy Register ValueTypeReg = GR->getSPIRVTypeID(Call->ReturnType); 836378630b4SVyacheslav Levytskyy // support cl_ext_float_atomics 837378630b4SVyacheslav Levytskyy if (Call->ReturnType->getOpcode() == SPIRV::OpTypeFloat) { 838378630b4SVyacheslav Levytskyy if (Opcode == SPIRV::OpAtomicIAdd) { 839378630b4SVyacheslav Levytskyy Opcode = SPIRV::OpAtomicFAddEXT; 840378630b4SVyacheslav Levytskyy } else if (Opcode == SPIRV::OpAtomicISub) { 841378630b4SVyacheslav Levytskyy // Translate OpAtomicISub applied to a floating type argument to 842378630b4SVyacheslav Levytskyy // OpAtomicFAddEXT with the negative value operand 843378630b4SVyacheslav Levytskyy Opcode = SPIRV::OpAtomicFAddEXT; 844378630b4SVyacheslav Levytskyy Register NegValueReg = 845378630b4SVyacheslav Levytskyy MRI->createGenericVirtualRegister(MRI->getType(ValueReg)); 84667d3ef74SVyacheslav Levytskyy MRI->setRegClass(NegValueReg, GR->getRegClass(Call->ReturnType)); 847378630b4SVyacheslav Levytskyy GR->assignSPIRVTypeToVReg(Call->ReturnType, NegValueReg, 848378630b4SVyacheslav Levytskyy MIRBuilder.getMF()); 849378630b4SVyacheslav Levytskyy MIRBuilder.buildInstr(TargetOpcode::G_FNEG) 850378630b4SVyacheslav Levytskyy .addDef(NegValueReg) 851378630b4SVyacheslav Levytskyy .addUse(ValueReg); 852378630b4SVyacheslav Levytskyy insertAssignInstr(NegValueReg, nullptr, Call->ReturnType, GR, MIRBuilder, 853378630b4SVyacheslav Levytskyy MIRBuilder.getMF().getRegInfo()); 854378630b4SVyacheslav Levytskyy ValueReg = NegValueReg; 855378630b4SVyacheslav Levytskyy } 856378630b4SVyacheslav Levytskyy } 857f61eb416SIlia Diachkov MIRBuilder.buildInstr(Opcode) 858f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 859378630b4SVyacheslav Levytskyy .addUse(ValueTypeReg) 860f61eb416SIlia Diachkov .addUse(PtrRegister) 861f61eb416SIlia Diachkov .addUse(ScopeRegister) 862f61eb416SIlia Diachkov .addUse(MemSemanticsReg) 863378630b4SVyacheslav Levytskyy .addUse(ValueReg); 864f61eb416SIlia Diachkov return true; 865f61eb416SIlia Diachkov } 866f61eb416SIlia Diachkov 867925768eeSVyacheslav Levytskyy /// Helper function for building an atomic floating-type instruction. 868925768eeSVyacheslav Levytskyy static bool buildAtomicFloatingRMWInst(const SPIRV::IncomingCall *Call, 869925768eeSVyacheslav Levytskyy unsigned Opcode, 870925768eeSVyacheslav Levytskyy MachineIRBuilder &MIRBuilder, 871925768eeSVyacheslav Levytskyy SPIRVGlobalRegistry *GR) { 872925768eeSVyacheslav Levytskyy assert(Call->Arguments.size() == 4 && 873925768eeSVyacheslav Levytskyy "Wrong number of atomic floating-type builtin"); 874925768eeSVyacheslav Levytskyy Register PtrReg = Call->Arguments[0]; 875925768eeSVyacheslav Levytskyy Register ScopeReg = Call->Arguments[1]; 876925768eeSVyacheslav Levytskyy Register MemSemanticsReg = Call->Arguments[2]; 877925768eeSVyacheslav Levytskyy Register ValueReg = Call->Arguments[3]; 878925768eeSVyacheslav Levytskyy MIRBuilder.buildInstr(Opcode) 879925768eeSVyacheslav Levytskyy .addDef(Call->ReturnRegister) 880925768eeSVyacheslav Levytskyy .addUse(GR->getSPIRVTypeID(Call->ReturnType)) 881925768eeSVyacheslav Levytskyy .addUse(PtrReg) 882925768eeSVyacheslav Levytskyy .addUse(ScopeReg) 883925768eeSVyacheslav Levytskyy .addUse(MemSemanticsReg) 884925768eeSVyacheslav Levytskyy .addUse(ValueReg); 885925768eeSVyacheslav Levytskyy return true; 886925768eeSVyacheslav Levytskyy } 887925768eeSVyacheslav Levytskyy 88887080898SMichal Paszkowski /// Helper function for building atomic flag instructions (e.g. 88987080898SMichal Paszkowski /// OpAtomicFlagTestAndSet). 89087080898SMichal Paszkowski static bool buildAtomicFlagInst(const SPIRV::IncomingCall *Call, 89187080898SMichal Paszkowski unsigned Opcode, MachineIRBuilder &MIRBuilder, 89287080898SMichal Paszkowski SPIRVGlobalRegistry *GR) { 893c2483ed5SVyacheslav Levytskyy bool IsSet = Opcode == SPIRV::OpAtomicFlagTestAndSet; 894c2483ed5SVyacheslav Levytskyy Register TypeReg = GR->getSPIRVTypeID(Call->ReturnType); 895c2483ed5SVyacheslav Levytskyy if (Call->isSpirvOp()) 896c2483ed5SVyacheslav Levytskyy return buildOpFromWrapper(MIRBuilder, Opcode, Call, 897c2483ed5SVyacheslav Levytskyy IsSet ? TypeReg : Register(0)); 898c2483ed5SVyacheslav Levytskyy 89974c66710SIlia Diachkov MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 90087080898SMichal Paszkowski Register PtrRegister = Call->Arguments[0]; 90187080898SMichal Paszkowski unsigned Semantics = SPIRV::MemorySemantics::SequentiallyConsistent; 90274c66710SIlia Diachkov Register MemSemanticsReg = 90374c66710SIlia Diachkov Call->Arguments.size() >= 2 ? Call->Arguments[1] : Register(); 90474c66710SIlia Diachkov MemSemanticsReg = buildMemSemanticsReg(MemSemanticsReg, PtrRegister, 90574c66710SIlia Diachkov Semantics, MIRBuilder, GR); 90687080898SMichal Paszkowski 90787080898SMichal Paszkowski assert((Opcode != SPIRV::OpAtomicFlagClear || 90887080898SMichal Paszkowski (Semantics != SPIRV::MemorySemantics::Acquire && 90987080898SMichal Paszkowski Semantics != SPIRV::MemorySemantics::AcquireRelease)) && 91087080898SMichal Paszkowski "Invalid memory order argument!"); 91187080898SMichal Paszkowski 91274c66710SIlia Diachkov Register ScopeRegister = 91374c66710SIlia Diachkov Call->Arguments.size() >= 3 ? Call->Arguments[2] : Register(); 91474c66710SIlia Diachkov ScopeRegister = 91574c66710SIlia Diachkov buildScopeReg(ScopeRegister, SPIRV::Scope::Device, MIRBuilder, GR, MRI); 91687080898SMichal Paszkowski 91787080898SMichal Paszkowski auto MIB = MIRBuilder.buildInstr(Opcode); 918c2483ed5SVyacheslav Levytskyy if (IsSet) 919c2483ed5SVyacheslav Levytskyy MIB.addDef(Call->ReturnRegister).addUse(TypeReg); 92087080898SMichal Paszkowski 92187080898SMichal Paszkowski MIB.addUse(PtrRegister).addUse(ScopeRegister).addUse(MemSemanticsReg); 92287080898SMichal Paszkowski return true; 92387080898SMichal Paszkowski } 92487080898SMichal Paszkowski 925f61eb416SIlia Diachkov /// Helper function for building barriers, i.e., memory/control ordering 926f61eb416SIlia Diachkov /// operations. 927f61eb416SIlia Diachkov static bool buildBarrierInst(const SPIRV::IncomingCall *Call, unsigned Opcode, 928f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 929f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 930bfe84f70SVyacheslav Levytskyy const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 931bfe84f70SVyacheslav Levytskyy const auto *ST = 932bfe84f70SVyacheslav Levytskyy static_cast<const SPIRVSubtarget *>(&MIRBuilder.getMF().getSubtarget()); 933bfe84f70SVyacheslav Levytskyy if ((Opcode == SPIRV::OpControlBarrierArriveINTEL || 934bfe84f70SVyacheslav Levytskyy Opcode == SPIRV::OpControlBarrierWaitINTEL) && 935bfe84f70SVyacheslav Levytskyy !ST->canUseExtension(SPIRV::Extension::SPV_INTEL_split_barrier)) { 936bfe84f70SVyacheslav Levytskyy std::string DiagMsg = std::string(Builtin->Name) + 937bfe84f70SVyacheslav Levytskyy ": the builtin requires the following SPIR-V " 938bfe84f70SVyacheslav Levytskyy "extension: SPV_INTEL_split_barrier"; 939bfe84f70SVyacheslav Levytskyy report_fatal_error(DiagMsg.c_str(), false); 940bfe84f70SVyacheslav Levytskyy } 941bfe84f70SVyacheslav Levytskyy 942c2483ed5SVyacheslav Levytskyy if (Call->isSpirvOp()) 94357f79371SVyacheslav Levytskyy return buildOpFromWrapper(MIRBuilder, Opcode, Call, Register(0)); 944c2483ed5SVyacheslav Levytskyy 94574c66710SIlia Diachkov MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 946f61eb416SIlia Diachkov unsigned MemFlags = getIConstVal(Call->Arguments[0], MRI); 947f61eb416SIlia Diachkov unsigned MemSemantics = SPIRV::MemorySemantics::None; 948f61eb416SIlia Diachkov 949f61eb416SIlia Diachkov if (MemFlags & SPIRV::CLK_LOCAL_MEM_FENCE) 950f61eb416SIlia Diachkov MemSemantics |= SPIRV::MemorySemantics::WorkgroupMemory; 951f61eb416SIlia Diachkov 952f61eb416SIlia Diachkov if (MemFlags & SPIRV::CLK_GLOBAL_MEM_FENCE) 953f61eb416SIlia Diachkov MemSemantics |= SPIRV::MemorySemantics::CrossWorkgroupMemory; 954f61eb416SIlia Diachkov 955f61eb416SIlia Diachkov if (MemFlags & SPIRV::CLK_IMAGE_MEM_FENCE) 956f61eb416SIlia Diachkov MemSemantics |= SPIRV::MemorySemantics::ImageMemory; 957f61eb416SIlia Diachkov 958bfe84f70SVyacheslav Levytskyy if (Opcode == SPIRV::OpMemoryBarrier) 959bfe84f70SVyacheslav Levytskyy MemSemantics = getSPIRVMemSemantics(static_cast<std::memory_order>( 960bfe84f70SVyacheslav Levytskyy getIConstVal(Call->Arguments[1], MRI))) | 961bfe84f70SVyacheslav Levytskyy MemSemantics; 962bfe84f70SVyacheslav Levytskyy else if (Opcode == SPIRV::OpControlBarrierArriveINTEL) 963bfe84f70SVyacheslav Levytskyy MemSemantics |= SPIRV::MemorySemantics::Release; 964bfe84f70SVyacheslav Levytskyy else if (Opcode == SPIRV::OpControlBarrierWaitINTEL) 965bfe84f70SVyacheslav Levytskyy MemSemantics |= SPIRV::MemorySemantics::Acquire; 966bfe84f70SVyacheslav Levytskyy else 967f61eb416SIlia Diachkov MemSemantics |= SPIRV::MemorySemantics::SequentiallyConsistent; 968f61eb416SIlia Diachkov 96967d3ef74SVyacheslav Levytskyy Register MemSemanticsReg = 97067d3ef74SVyacheslav Levytskyy MemFlags == MemSemantics 97167d3ef74SVyacheslav Levytskyy ? Call->Arguments[0] 97267d3ef74SVyacheslav Levytskyy : buildConstantIntReg32(MemSemantics, MIRBuilder, GR); 973f61eb416SIlia Diachkov Register ScopeReg; 974f61eb416SIlia Diachkov SPIRV::Scope::Scope Scope = SPIRV::Scope::Workgroup; 975f61eb416SIlia Diachkov SPIRV::Scope::Scope MemScope = Scope; 976f61eb416SIlia Diachkov if (Call->Arguments.size() >= 2) { 977f61eb416SIlia Diachkov assert( 978f61eb416SIlia Diachkov ((Opcode != SPIRV::OpMemoryBarrier && Call->Arguments.size() == 2) || 979f61eb416SIlia Diachkov (Opcode == SPIRV::OpMemoryBarrier && Call->Arguments.size() == 3)) && 980f61eb416SIlia Diachkov "Extra args for explicitly scoped barrier"); 981f61eb416SIlia Diachkov Register ScopeArg = (Opcode == SPIRV::OpMemoryBarrier) ? Call->Arguments[2] 982f61eb416SIlia Diachkov : Call->Arguments[1]; 983f61eb416SIlia Diachkov SPIRV::CLMemoryScope CLScope = 984f61eb416SIlia Diachkov static_cast<SPIRV::CLMemoryScope>(getIConstVal(ScopeArg, MRI)); 985f61eb416SIlia Diachkov MemScope = getSPIRVScope(CLScope); 986f61eb416SIlia Diachkov if (!(MemFlags & SPIRV::CLK_LOCAL_MEM_FENCE) || 987f61eb416SIlia Diachkov (Opcode == SPIRV::OpMemoryBarrier)) 988f61eb416SIlia Diachkov Scope = MemScope; 98967d3ef74SVyacheslav Levytskyy if (CLScope == static_cast<unsigned>(Scope)) 990f61eb416SIlia Diachkov ScopeReg = Call->Arguments[1]; 991f61eb416SIlia Diachkov } 992f61eb416SIlia Diachkov 993f61eb416SIlia Diachkov if (!ScopeReg.isValid()) 99467d3ef74SVyacheslav Levytskyy ScopeReg = buildConstantIntReg32(Scope, MIRBuilder, GR); 995f61eb416SIlia Diachkov 996f61eb416SIlia Diachkov auto MIB = MIRBuilder.buildInstr(Opcode).addUse(ScopeReg); 997f61eb416SIlia Diachkov if (Opcode != SPIRV::OpMemoryBarrier) 99867d3ef74SVyacheslav Levytskyy MIB.addUse(buildConstantIntReg32(MemScope, MIRBuilder, GR)); 999f61eb416SIlia Diachkov MIB.addUse(MemSemanticsReg); 1000f61eb416SIlia Diachkov return true; 1001f61eb416SIlia Diachkov } 1002f61eb416SIlia Diachkov 1003f61eb416SIlia Diachkov static unsigned getNumComponentsForDim(SPIRV::Dim::Dim dim) { 1004f61eb416SIlia Diachkov switch (dim) { 1005f61eb416SIlia Diachkov case SPIRV::Dim::DIM_1D: 1006f61eb416SIlia Diachkov case SPIRV::Dim::DIM_Buffer: 1007f61eb416SIlia Diachkov return 1; 1008f61eb416SIlia Diachkov case SPIRV::Dim::DIM_2D: 1009f61eb416SIlia Diachkov case SPIRV::Dim::DIM_Cube: 1010f61eb416SIlia Diachkov case SPIRV::Dim::DIM_Rect: 1011f61eb416SIlia Diachkov return 2; 1012f61eb416SIlia Diachkov case SPIRV::Dim::DIM_3D: 1013f61eb416SIlia Diachkov return 3; 1014f61eb416SIlia Diachkov default: 1015925768eeSVyacheslav Levytskyy report_fatal_error("Cannot get num components for given Dim"); 1016f61eb416SIlia Diachkov } 1017f61eb416SIlia Diachkov } 1018f61eb416SIlia Diachkov 1019f61eb416SIlia Diachkov /// Helper function for obtaining the number of size components. 1020f61eb416SIlia Diachkov static unsigned getNumSizeComponents(SPIRVType *imgType) { 1021f61eb416SIlia Diachkov assert(imgType->getOpcode() == SPIRV::OpTypeImage); 1022f61eb416SIlia Diachkov auto dim = static_cast<SPIRV::Dim::Dim>(imgType->getOperand(2).getImm()); 1023f61eb416SIlia Diachkov unsigned numComps = getNumComponentsForDim(dim); 1024f61eb416SIlia Diachkov bool arrayed = imgType->getOperand(4).getImm() == 1; 1025f61eb416SIlia Diachkov return arrayed ? numComps + 1 : numComps; 1026f61eb416SIlia Diachkov } 1027f61eb416SIlia Diachkov 1028f61eb416SIlia Diachkov //===----------------------------------------------------------------------===// 1029f61eb416SIlia Diachkov // Implementation functions for each builtin group 1030f61eb416SIlia Diachkov //===----------------------------------------------------------------------===// 1031f61eb416SIlia Diachkov 1032f61eb416SIlia Diachkov static bool generateExtInst(const SPIRV::IncomingCall *Call, 1033f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 1034f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 1035f61eb416SIlia Diachkov // Lookup the extended instruction number in the TableGen records. 1036f61eb416SIlia Diachkov const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 1037f61eb416SIlia Diachkov uint32_t Number = 1038f61eb416SIlia Diachkov SPIRV::lookupExtendedBuiltin(Builtin->Name, Builtin->Set)->Number; 1039f61eb416SIlia Diachkov 1040f61eb416SIlia Diachkov // Build extended instruction. 1041f61eb416SIlia Diachkov auto MIB = 1042f61eb416SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpExtInst) 1043f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 1044f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(Call->ReturnType)) 1045f61eb416SIlia Diachkov .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std)) 1046f61eb416SIlia Diachkov .addImm(Number); 1047f61eb416SIlia Diachkov 1048f61eb416SIlia Diachkov for (auto Argument : Call->Arguments) 1049f61eb416SIlia Diachkov MIB.addUse(Argument); 1050f61eb416SIlia Diachkov return true; 1051f61eb416SIlia Diachkov } 1052f61eb416SIlia Diachkov 1053f61eb416SIlia Diachkov static bool generateRelationalInst(const SPIRV::IncomingCall *Call, 1054f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 1055f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 1056f61eb416SIlia Diachkov // Lookup the instruction opcode in the TableGen records. 1057f61eb416SIlia Diachkov const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 1058f61eb416SIlia Diachkov unsigned Opcode = 1059f61eb416SIlia Diachkov SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode; 1060f61eb416SIlia Diachkov 1061f61eb416SIlia Diachkov Register CompareRegister; 1062f61eb416SIlia Diachkov SPIRVType *RelationType; 1063f61eb416SIlia Diachkov std::tie(CompareRegister, RelationType) = 1064f61eb416SIlia Diachkov buildBoolRegister(MIRBuilder, Call->ReturnType, GR); 1065f61eb416SIlia Diachkov 1066f61eb416SIlia Diachkov // Build relational instruction. 1067f61eb416SIlia Diachkov auto MIB = MIRBuilder.buildInstr(Opcode) 1068f61eb416SIlia Diachkov .addDef(CompareRegister) 1069f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(RelationType)); 1070f61eb416SIlia Diachkov 1071f61eb416SIlia Diachkov for (auto Argument : Call->Arguments) 1072f61eb416SIlia Diachkov MIB.addUse(Argument); 1073f61eb416SIlia Diachkov 1074f61eb416SIlia Diachkov // Build select instruction. 1075f61eb416SIlia Diachkov return buildSelectInst(MIRBuilder, Call->ReturnRegister, CompareRegister, 1076f61eb416SIlia Diachkov Call->ReturnType, GR); 1077f61eb416SIlia Diachkov } 1078f61eb416SIlia Diachkov 1079f61eb416SIlia Diachkov static bool generateGroupInst(const SPIRV::IncomingCall *Call, 1080f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 1081f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 1082f61eb416SIlia Diachkov const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 1083f61eb416SIlia Diachkov const SPIRV::GroupBuiltin *GroupBuiltin = 1084f61eb416SIlia Diachkov SPIRV::lookupGroupBuiltin(Builtin->Name); 10854baea8b3SVyacheslav Levytskyy 108674c66710SIlia Diachkov MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 10874baea8b3SVyacheslav Levytskyy if (Call->isSpirvOp()) { 10884baea8b3SVyacheslav Levytskyy if (GroupBuiltin->NoGroupOperation) 10894baea8b3SVyacheslav Levytskyy return buildOpFromWrapper(MIRBuilder, GroupBuiltin->Opcode, Call, 10904baea8b3SVyacheslav Levytskyy GR->getSPIRVTypeID(Call->ReturnType)); 10914baea8b3SVyacheslav Levytskyy 10924baea8b3SVyacheslav Levytskyy // Group Operation is a literal 10934baea8b3SVyacheslav Levytskyy Register GroupOpReg = Call->Arguments[1]; 10944baea8b3SVyacheslav Levytskyy const MachineInstr *MI = getDefInstrMaybeConstant(GroupOpReg, MRI); 10954baea8b3SVyacheslav Levytskyy if (!MI || MI->getOpcode() != TargetOpcode::G_CONSTANT) 10964baea8b3SVyacheslav Levytskyy report_fatal_error( 10974baea8b3SVyacheslav Levytskyy "Group Operation parameter must be an integer constant"); 10984baea8b3SVyacheslav Levytskyy uint64_t GrpOp = MI->getOperand(1).getCImm()->getValue().getZExtValue(); 10994baea8b3SVyacheslav Levytskyy Register ScopeReg = Call->Arguments[0]; 110024cee1c4SVyacheslav Levytskyy auto MIB = MIRBuilder.buildInstr(GroupBuiltin->Opcode) 11014baea8b3SVyacheslav Levytskyy .addDef(Call->ReturnRegister) 11024baea8b3SVyacheslav Levytskyy .addUse(GR->getSPIRVTypeID(Call->ReturnType)) 11034baea8b3SVyacheslav Levytskyy .addUse(ScopeReg) 110424cee1c4SVyacheslav Levytskyy .addImm(GrpOp); 110567d3ef74SVyacheslav Levytskyy for (unsigned i = 2; i < Call->Arguments.size(); ++i) 110667d3ef74SVyacheslav Levytskyy MIB.addUse(Call->Arguments[i]); 11074baea8b3SVyacheslav Levytskyy return true; 11084baea8b3SVyacheslav Levytskyy } 11094baea8b3SVyacheslav Levytskyy 1110f61eb416SIlia Diachkov Register Arg0; 1111f61eb416SIlia Diachkov if (GroupBuiltin->HasBoolArg) { 111223c72e93SVyacheslav Levytskyy SPIRVType *BoolType = GR->getOrCreateSPIRVBoolType(MIRBuilder); 111323c72e93SVyacheslav Levytskyy Register BoolReg = Call->Arguments[0]; 111423c72e93SVyacheslav Levytskyy SPIRVType *BoolRegType = GR->getSPIRVTypeForVReg(BoolReg); 111523c72e93SVyacheslav Levytskyy if (!BoolRegType) 111623c72e93SVyacheslav Levytskyy report_fatal_error("Can't find a register's type definition"); 111723c72e93SVyacheslav Levytskyy MachineInstr *ArgInstruction = getDefInstrMaybeConstant(BoolReg, MRI); 111823c72e93SVyacheslav Levytskyy if (ArgInstruction->getOpcode() == TargetOpcode::G_CONSTANT) { 111923c72e93SVyacheslav Levytskyy if (BoolRegType->getOpcode() != SPIRV::OpTypeBool) 112023c72e93SVyacheslav Levytskyy Arg0 = GR->buildConstantInt(getIConstVal(BoolReg, MRI), MIRBuilder, 112123c72e93SVyacheslav Levytskyy BoolType); 112223c72e93SVyacheslav Levytskyy } else { 112323c72e93SVyacheslav Levytskyy if (BoolRegType->getOpcode() == SPIRV::OpTypeInt) { 112423c72e93SVyacheslav Levytskyy Arg0 = MRI->createGenericVirtualRegister(LLT::scalar(1)); 112567d3ef74SVyacheslav Levytskyy MRI->setRegClass(Arg0, &SPIRV::iIDRegClass); 112623c72e93SVyacheslav Levytskyy GR->assignSPIRVTypeToVReg(BoolType, Arg0, MIRBuilder.getMF()); 112723c72e93SVyacheslav Levytskyy MIRBuilder.buildICmp(CmpInst::ICMP_NE, Arg0, BoolReg, 112823c72e93SVyacheslav Levytskyy GR->buildConstantInt(0, MIRBuilder, BoolRegType)); 112923c72e93SVyacheslav Levytskyy insertAssignInstr(Arg0, nullptr, BoolType, GR, MIRBuilder, 113023c72e93SVyacheslav Levytskyy MIRBuilder.getMF().getRegInfo()); 113123c72e93SVyacheslav Levytskyy } else if (BoolRegType->getOpcode() != SPIRV::OpTypeBool) { 113223c72e93SVyacheslav Levytskyy report_fatal_error("Expect a boolean argument"); 113323c72e93SVyacheslav Levytskyy } 113423c72e93SVyacheslav Levytskyy // if BoolReg is a boolean register, we don't need to do anything 113523c72e93SVyacheslav Levytskyy } 1136f61eb416SIlia Diachkov } 1137f61eb416SIlia Diachkov 1138f61eb416SIlia Diachkov Register GroupResultRegister = Call->ReturnRegister; 1139f61eb416SIlia Diachkov SPIRVType *GroupResultType = Call->ReturnType; 1140f61eb416SIlia Diachkov 1141f61eb416SIlia Diachkov // TODO: maybe we need to check whether the result type is already boolean 1142f61eb416SIlia Diachkov // and in this case do not insert select instruction. 1143f61eb416SIlia Diachkov const bool HasBoolReturnTy = 1144f61eb416SIlia Diachkov GroupBuiltin->IsElect || GroupBuiltin->IsAllOrAny || 1145f61eb416SIlia Diachkov GroupBuiltin->IsAllEqual || GroupBuiltin->IsLogical || 1146f61eb416SIlia Diachkov GroupBuiltin->IsInverseBallot || GroupBuiltin->IsBallotBitExtract; 1147f61eb416SIlia Diachkov 1148f61eb416SIlia Diachkov if (HasBoolReturnTy) 1149f61eb416SIlia Diachkov std::tie(GroupResultRegister, GroupResultType) = 1150f61eb416SIlia Diachkov buildBoolRegister(MIRBuilder, Call->ReturnType, GR); 1151f61eb416SIlia Diachkov 1152395f9ce3SKazu Hirata auto Scope = Builtin->Name.starts_with("sub_group") ? SPIRV::Scope::Subgroup 1153f61eb416SIlia Diachkov : SPIRV::Scope::Workgroup; 115467d3ef74SVyacheslav Levytskyy Register ScopeRegister = buildConstantIntReg32(Scope, MIRBuilder, GR); 1155f61eb416SIlia Diachkov 11562fc7a727SVyacheslav Levytskyy Register VecReg; 11572fc7a727SVyacheslav Levytskyy if (GroupBuiltin->Opcode == SPIRV::OpGroupBroadcast && 11582fc7a727SVyacheslav Levytskyy Call->Arguments.size() > 2) { 11592fc7a727SVyacheslav Levytskyy // For OpGroupBroadcast "LocalId must be an integer datatype. It must be a 11602fc7a727SVyacheslav Levytskyy // scalar, a vector with 2 components, or a vector with 3 components.", 11612fc7a727SVyacheslav Levytskyy // meaning that we must create a vector from the function arguments if 11622fc7a727SVyacheslav Levytskyy // it's a work_group_broadcast(val, local_id_x, local_id_y) or 11632fc7a727SVyacheslav Levytskyy // work_group_broadcast(val, local_id_x, local_id_y, local_id_z) call. 11642fc7a727SVyacheslav Levytskyy Register ElemReg = Call->Arguments[1]; 11652fc7a727SVyacheslav Levytskyy SPIRVType *ElemType = GR->getSPIRVTypeForVReg(ElemReg); 11662fc7a727SVyacheslav Levytskyy if (!ElemType || ElemType->getOpcode() != SPIRV::OpTypeInt) 11672fc7a727SVyacheslav Levytskyy report_fatal_error("Expect an integer <LocalId> argument"); 11682fc7a727SVyacheslav Levytskyy unsigned VecLen = Call->Arguments.size() - 1; 11692fc7a727SVyacheslav Levytskyy VecReg = MRI->createGenericVirtualRegister( 11702fc7a727SVyacheslav Levytskyy LLT::fixed_vector(VecLen, MRI->getType(ElemReg))); 11712fc7a727SVyacheslav Levytskyy MRI->setRegClass(VecReg, &SPIRV::vIDRegClass); 11722fc7a727SVyacheslav Levytskyy SPIRVType *VecType = 11732fc7a727SVyacheslav Levytskyy GR->getOrCreateSPIRVVectorType(ElemType, VecLen, MIRBuilder); 11742fc7a727SVyacheslav Levytskyy GR->assignSPIRVTypeToVReg(VecType, VecReg, MIRBuilder.getMF()); 11752fc7a727SVyacheslav Levytskyy auto MIB = 11762fc7a727SVyacheslav Levytskyy MIRBuilder.buildInstr(TargetOpcode::G_BUILD_VECTOR).addDef(VecReg); 11772fc7a727SVyacheslav Levytskyy for (unsigned i = 1; i < Call->Arguments.size(); i++) { 11782fc7a727SVyacheslav Levytskyy MIB.addUse(Call->Arguments[i]); 1179978de2d6SVyacheslav Levytskyy setRegClassIfNull(Call->Arguments[i], MRI, GR); 11802fc7a727SVyacheslav Levytskyy } 11812fc7a727SVyacheslav Levytskyy insertAssignInstr(VecReg, nullptr, VecType, GR, MIRBuilder, 11822fc7a727SVyacheslav Levytskyy MIRBuilder.getMF().getRegInfo()); 11832fc7a727SVyacheslav Levytskyy } 11842fc7a727SVyacheslav Levytskyy 1185f61eb416SIlia Diachkov // Build work/sub group instruction. 1186f61eb416SIlia Diachkov auto MIB = MIRBuilder.buildInstr(GroupBuiltin->Opcode) 1187f61eb416SIlia Diachkov .addDef(GroupResultRegister) 1188f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(GroupResultType)) 1189f61eb416SIlia Diachkov .addUse(ScopeRegister); 1190f61eb416SIlia Diachkov 1191f61eb416SIlia Diachkov if (!GroupBuiltin->NoGroupOperation) 1192f61eb416SIlia Diachkov MIB.addImm(GroupBuiltin->GroupOperation); 1193f61eb416SIlia Diachkov if (Call->Arguments.size() > 0) { 1194f61eb416SIlia Diachkov MIB.addUse(Arg0.isValid() ? Arg0 : Call->Arguments[0]); 1195978de2d6SVyacheslav Levytskyy setRegClassIfNull(Call->Arguments[0], MRI, GR); 11962fc7a727SVyacheslav Levytskyy if (VecReg.isValid()) 11972fc7a727SVyacheslav Levytskyy MIB.addUse(VecReg); 11982fc7a727SVyacheslav Levytskyy else 119967d3ef74SVyacheslav Levytskyy for (unsigned i = 1; i < Call->Arguments.size(); i++) 1200f61eb416SIlia Diachkov MIB.addUse(Call->Arguments[i]); 1201f61eb416SIlia Diachkov } 1202f61eb416SIlia Diachkov 1203f61eb416SIlia Diachkov // Build select instruction. 1204f61eb416SIlia Diachkov if (HasBoolReturnTy) 1205f61eb416SIlia Diachkov buildSelectInst(MIRBuilder, Call->ReturnRegister, GroupResultRegister, 1206f61eb416SIlia Diachkov Call->ReturnType, GR); 1207f61eb416SIlia Diachkov return true; 1208f61eb416SIlia Diachkov } 1209f61eb416SIlia Diachkov 1210b221b973SVyacheslav Levytskyy static bool generateIntelSubgroupsInst(const SPIRV::IncomingCall *Call, 1211b221b973SVyacheslav Levytskyy MachineIRBuilder &MIRBuilder, 1212b221b973SVyacheslav Levytskyy SPIRVGlobalRegistry *GR) { 1213b221b973SVyacheslav Levytskyy const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 1214b221b973SVyacheslav Levytskyy MachineFunction &MF = MIRBuilder.getMF(); 1215b221b973SVyacheslav Levytskyy const auto *ST = static_cast<const SPIRVSubtarget *>(&MF.getSubtarget()); 12164a6ecd38SViktoria Maximova const SPIRV::IntelSubgroupsBuiltin *IntelSubgroups = 12174a6ecd38SViktoria Maximova SPIRV::lookupIntelSubgroupsBuiltin(Builtin->Name); 12184a6ecd38SViktoria Maximova 12194a6ecd38SViktoria Maximova if (IntelSubgroups->IsMedia && 12204a6ecd38SViktoria Maximova !ST->canUseExtension(SPIRV::Extension::SPV_INTEL_media_block_io)) { 12214a6ecd38SViktoria Maximova std::string DiagMsg = std::string(Builtin->Name) + 12224a6ecd38SViktoria Maximova ": the builtin requires the following SPIR-V " 12234a6ecd38SViktoria Maximova "extension: SPV_INTEL_media_block_io"; 12244a6ecd38SViktoria Maximova report_fatal_error(DiagMsg.c_str(), false); 12254a6ecd38SViktoria Maximova } else if (!IntelSubgroups->IsMedia && 12264a6ecd38SViktoria Maximova !ST->canUseExtension(SPIRV::Extension::SPV_INTEL_subgroups)) { 1227b221b973SVyacheslav Levytskyy std::string DiagMsg = std::string(Builtin->Name) + 1228b221b973SVyacheslav Levytskyy ": the builtin requires the following SPIR-V " 1229b221b973SVyacheslav Levytskyy "extension: SPV_INTEL_subgroups"; 1230b221b973SVyacheslav Levytskyy report_fatal_error(DiagMsg.c_str(), false); 1231b221b973SVyacheslav Levytskyy } 1232b221b973SVyacheslav Levytskyy 1233b221b973SVyacheslav Levytskyy uint32_t OpCode = IntelSubgroups->Opcode; 123437cf0473SVyacheslav Levytskyy if (Call->isSpirvOp()) { 123537cf0473SVyacheslav Levytskyy bool IsSet = OpCode != SPIRV::OpSubgroupBlockWriteINTEL && 12364a6ecd38SViktoria Maximova OpCode != SPIRV::OpSubgroupImageBlockWriteINTEL && 12374a6ecd38SViktoria Maximova OpCode != SPIRV::OpSubgroupImageMediaBlockWriteINTEL; 123837cf0473SVyacheslav Levytskyy return buildOpFromWrapper(MIRBuilder, OpCode, Call, 123937cf0473SVyacheslav Levytskyy IsSet ? GR->getSPIRVTypeID(Call->ReturnType) 124037cf0473SVyacheslav Levytskyy : Register(0)); 124137cf0473SVyacheslav Levytskyy } 124237cf0473SVyacheslav Levytskyy 1243b221b973SVyacheslav Levytskyy if (IntelSubgroups->IsBlock) { 1244b221b973SVyacheslav Levytskyy // Minimal number or arguments set in TableGen records is 1 1245b221b973SVyacheslav Levytskyy if (SPIRVType *Arg0Type = GR->getSPIRVTypeForVReg(Call->Arguments[0])) { 1246b221b973SVyacheslav Levytskyy if (Arg0Type->getOpcode() == SPIRV::OpTypeImage) { 1247b221b973SVyacheslav Levytskyy // TODO: add required validation from the specification: 1248b221b973SVyacheslav Levytskyy // "'Image' must be an object whose type is OpTypeImage with a 'Sampled' 1249b221b973SVyacheslav Levytskyy // operand of 0 or 2. If the 'Sampled' operand is 2, then some 1250b221b973SVyacheslav Levytskyy // dimensions require a capability." 1251b221b973SVyacheslav Levytskyy switch (OpCode) { 1252b221b973SVyacheslav Levytskyy case SPIRV::OpSubgroupBlockReadINTEL: 1253b221b973SVyacheslav Levytskyy OpCode = SPIRV::OpSubgroupImageBlockReadINTEL; 1254b221b973SVyacheslav Levytskyy break; 1255b221b973SVyacheslav Levytskyy case SPIRV::OpSubgroupBlockWriteINTEL: 1256b221b973SVyacheslav Levytskyy OpCode = SPIRV::OpSubgroupImageBlockWriteINTEL; 1257b221b973SVyacheslav Levytskyy break; 1258b221b973SVyacheslav Levytskyy } 1259b221b973SVyacheslav Levytskyy } 1260b221b973SVyacheslav Levytskyy } 1261b221b973SVyacheslav Levytskyy } 1262b221b973SVyacheslav Levytskyy 1263b221b973SVyacheslav Levytskyy // TODO: opaque pointers types should be eventually resolved in such a way 1264b221b973SVyacheslav Levytskyy // that validation of block read is enabled with respect to the following 1265b221b973SVyacheslav Levytskyy // specification requirement: 1266b221b973SVyacheslav Levytskyy // "'Result Type' may be a scalar or vector type, and its component type must 1267b221b973SVyacheslav Levytskyy // be equal to the type pointed to by 'Ptr'." 1268b221b973SVyacheslav Levytskyy // For example, function parameter type should not be default i8 pointer, but 1269b221b973SVyacheslav Levytskyy // depend on the result type of the instruction where it is used as a pointer 1270b221b973SVyacheslav Levytskyy // argument of OpSubgroupBlockReadINTEL 1271b221b973SVyacheslav Levytskyy 1272b221b973SVyacheslav Levytskyy // Build Intel subgroups instruction 1273b221b973SVyacheslav Levytskyy MachineInstrBuilder MIB = 1274b221b973SVyacheslav Levytskyy IntelSubgroups->IsWrite 1275b221b973SVyacheslav Levytskyy ? MIRBuilder.buildInstr(OpCode) 1276b221b973SVyacheslav Levytskyy : MIRBuilder.buildInstr(OpCode) 1277b221b973SVyacheslav Levytskyy .addDef(Call->ReturnRegister) 1278b221b973SVyacheslav Levytskyy .addUse(GR->getSPIRVTypeID(Call->ReturnType)); 127967d3ef74SVyacheslav Levytskyy for (size_t i = 0; i < Call->Arguments.size(); ++i) 1280b221b973SVyacheslav Levytskyy MIB.addUse(Call->Arguments[i]); 1281b221b973SVyacheslav Levytskyy return true; 1282b221b973SVyacheslav Levytskyy } 1283b221b973SVyacheslav Levytskyy 128466ebda46SVyacheslav Levytskyy static bool generateGroupUniformInst(const SPIRV::IncomingCall *Call, 128566ebda46SVyacheslav Levytskyy MachineIRBuilder &MIRBuilder, 128666ebda46SVyacheslav Levytskyy SPIRVGlobalRegistry *GR) { 128766ebda46SVyacheslav Levytskyy const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 128866ebda46SVyacheslav Levytskyy MachineFunction &MF = MIRBuilder.getMF(); 128966ebda46SVyacheslav Levytskyy const auto *ST = static_cast<const SPIRVSubtarget *>(&MF.getSubtarget()); 129066ebda46SVyacheslav Levytskyy if (!ST->canUseExtension( 129166ebda46SVyacheslav Levytskyy SPIRV::Extension::SPV_KHR_uniform_group_instructions)) { 129266ebda46SVyacheslav Levytskyy std::string DiagMsg = std::string(Builtin->Name) + 129366ebda46SVyacheslav Levytskyy ": the builtin requires the following SPIR-V " 129466ebda46SVyacheslav Levytskyy "extension: SPV_KHR_uniform_group_instructions"; 129566ebda46SVyacheslav Levytskyy report_fatal_error(DiagMsg.c_str(), false); 129666ebda46SVyacheslav Levytskyy } 129766ebda46SVyacheslav Levytskyy const SPIRV::GroupUniformBuiltin *GroupUniform = 129866ebda46SVyacheslav Levytskyy SPIRV::lookupGroupUniformBuiltin(Builtin->Name); 129966ebda46SVyacheslav Levytskyy MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 130066ebda46SVyacheslav Levytskyy 130166ebda46SVyacheslav Levytskyy Register GroupResultReg = Call->ReturnRegister; 130266ebda46SVyacheslav Levytskyy Register ScopeReg = Call->Arguments[0]; 130367d3ef74SVyacheslav Levytskyy Register ValueReg = Call->Arguments[2]; 130466ebda46SVyacheslav Levytskyy 130566ebda46SVyacheslav Levytskyy // Group Operation 130666ebda46SVyacheslav Levytskyy Register ConstGroupOpReg = Call->Arguments[1]; 130766ebda46SVyacheslav Levytskyy const MachineInstr *Const = getDefInstrMaybeConstant(ConstGroupOpReg, MRI); 130866ebda46SVyacheslav Levytskyy if (!Const || Const->getOpcode() != TargetOpcode::G_CONSTANT) 130966ebda46SVyacheslav Levytskyy report_fatal_error( 131066ebda46SVyacheslav Levytskyy "expect a constant group operation for a uniform group instruction", 131166ebda46SVyacheslav Levytskyy false); 131266ebda46SVyacheslav Levytskyy const MachineOperand &ConstOperand = Const->getOperand(1); 131366ebda46SVyacheslav Levytskyy if (!ConstOperand.isCImm()) 131466ebda46SVyacheslav Levytskyy report_fatal_error("uniform group instructions: group operation must be an " 131566ebda46SVyacheslav Levytskyy "integer constant", 131666ebda46SVyacheslav Levytskyy false); 131766ebda46SVyacheslav Levytskyy 131866ebda46SVyacheslav Levytskyy auto MIB = MIRBuilder.buildInstr(GroupUniform->Opcode) 131966ebda46SVyacheslav Levytskyy .addDef(GroupResultReg) 132066ebda46SVyacheslav Levytskyy .addUse(GR->getSPIRVTypeID(Call->ReturnType)) 132166ebda46SVyacheslav Levytskyy .addUse(ScopeReg); 132266ebda46SVyacheslav Levytskyy addNumImm(ConstOperand.getCImm()->getValue(), MIB); 132366ebda46SVyacheslav Levytskyy MIB.addUse(ValueReg); 132466ebda46SVyacheslav Levytskyy 132566ebda46SVyacheslav Levytskyy return true; 132666ebda46SVyacheslav Levytskyy } 132766ebda46SVyacheslav Levytskyy 132889c23f76SSven van Haastregt static bool generateKernelClockInst(const SPIRV::IncomingCall *Call, 132989c23f76SSven van Haastregt MachineIRBuilder &MIRBuilder, 133089c23f76SSven van Haastregt SPIRVGlobalRegistry *GR) { 133189c23f76SSven van Haastregt const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 133289c23f76SSven van Haastregt MachineFunction &MF = MIRBuilder.getMF(); 133389c23f76SSven van Haastregt const auto *ST = static_cast<const SPIRVSubtarget *>(&MF.getSubtarget()); 133489c23f76SSven van Haastregt if (!ST->canUseExtension(SPIRV::Extension::SPV_KHR_shader_clock)) { 133589c23f76SSven van Haastregt std::string DiagMsg = std::string(Builtin->Name) + 133689c23f76SSven van Haastregt ": the builtin requires the following SPIR-V " 133789c23f76SSven van Haastregt "extension: SPV_KHR_shader_clock"; 133889c23f76SSven van Haastregt report_fatal_error(DiagMsg.c_str(), false); 133989c23f76SSven van Haastregt } 134089c23f76SSven van Haastregt 134189c23f76SSven van Haastregt Register ResultReg = Call->ReturnRegister; 134289c23f76SSven van Haastregt 134389c23f76SSven van Haastregt // Deduce the `Scope` operand from the builtin function name. 134489c23f76SSven van Haastregt SPIRV::Scope::Scope ScopeArg = 134589c23f76SSven van Haastregt StringSwitch<SPIRV::Scope::Scope>(Builtin->Name) 134689c23f76SSven van Haastregt .EndsWith("device", SPIRV::Scope::Scope::Device) 134789c23f76SSven van Haastregt .EndsWith("work_group", SPIRV::Scope::Scope::Workgroup) 134889c23f76SSven van Haastregt .EndsWith("sub_group", SPIRV::Scope::Scope::Subgroup); 134967d3ef74SVyacheslav Levytskyy Register ScopeReg = buildConstantIntReg32(ScopeArg, MIRBuilder, GR); 135089c23f76SSven van Haastregt 135189c23f76SSven van Haastregt MIRBuilder.buildInstr(SPIRV::OpReadClockKHR) 135289c23f76SSven van Haastregt .addDef(ResultReg) 135389c23f76SSven van Haastregt .addUse(GR->getSPIRVTypeID(Call->ReturnType)) 135489c23f76SSven van Haastregt .addUse(ScopeReg); 135589c23f76SSven van Haastregt 135689c23f76SSven van Haastregt return true; 135789c23f76SSven van Haastregt } 135889c23f76SSven van Haastregt 1359f61eb416SIlia Diachkov // These queries ask for a single size_t result for a given dimension index, e.g 13603544d200SIlia Diachkov // size_t get_global_id(uint dimindex). In SPIR-V, the builtins corresonding to 1361f61eb416SIlia Diachkov // these values are all vec3 types, so we need to extract the correct index or 1362f61eb416SIlia Diachkov // return defaultVal (0 or 1 depending on the query). We also handle extending 1363f61eb416SIlia Diachkov // or tuncating in case size_t does not match the expected result type's 1364f61eb416SIlia Diachkov // bitwidth. 1365f61eb416SIlia Diachkov // 1366f61eb416SIlia Diachkov // For a constant index >= 3 we generate: 1367f61eb416SIlia Diachkov // %res = OpConstant %SizeT 0 1368f61eb416SIlia Diachkov // 1369f61eb416SIlia Diachkov // For other indices we generate: 1370f61eb416SIlia Diachkov // %g = OpVariable %ptr_V3_SizeT Input 1371f61eb416SIlia Diachkov // OpDecorate %g BuiltIn XXX 1372f61eb416SIlia Diachkov // OpDecorate %g LinkageAttributes "__spirv_BuiltInXXX" 1373f61eb416SIlia Diachkov // OpDecorate %g Constant 1374f61eb416SIlia Diachkov // %loadedVec = OpLoad %V3_SizeT %g 1375f61eb416SIlia Diachkov // 1376f61eb416SIlia Diachkov // Then, if the index is constant < 3, we generate: 1377f61eb416SIlia Diachkov // %res = OpCompositeExtract %SizeT %loadedVec idx 1378f61eb416SIlia Diachkov // If the index is dynamic, we generate: 1379f61eb416SIlia Diachkov // %tmp = OpVectorExtractDynamic %SizeT %loadedVec %idx 1380f61eb416SIlia Diachkov // %cmp = OpULessThan %bool %idx %const_3 1381f61eb416SIlia Diachkov // %res = OpSelect %SizeT %cmp %tmp %const_0 1382f61eb416SIlia Diachkov // 1383f61eb416SIlia Diachkov // If the bitwidth of %res does not match the expected return type, we add an 1384f61eb416SIlia Diachkov // extend or truncate. 1385f61eb416SIlia Diachkov static bool genWorkgroupQuery(const SPIRV::IncomingCall *Call, 1386f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 1387f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR, 1388f61eb416SIlia Diachkov SPIRV::BuiltIn::BuiltIn BuiltinValue, 1389f61eb416SIlia Diachkov uint64_t DefaultValue) { 1390f61eb416SIlia Diachkov Register IndexRegister = Call->Arguments[0]; 1391f61eb416SIlia Diachkov const unsigned ResultWidth = Call->ReturnType->getOperand(1).getImm(); 1392f61eb416SIlia Diachkov const unsigned PointerSize = GR->getPointerSize(); 1393f61eb416SIlia Diachkov const SPIRVType *PointerSizeType = 1394f61eb416SIlia Diachkov GR->getOrCreateSPIRVIntegerType(PointerSize, MIRBuilder); 1395f61eb416SIlia Diachkov MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 1396f61eb416SIlia Diachkov auto IndexInstruction = getDefInstrMaybeConstant(IndexRegister, MRI); 1397f61eb416SIlia Diachkov 1398f61eb416SIlia Diachkov // Set up the final register to do truncation or extension on at the end. 1399f61eb416SIlia Diachkov Register ToTruncate = Call->ReturnRegister; 1400f61eb416SIlia Diachkov 1401f61eb416SIlia Diachkov // If the index is constant, we can statically determine if it is in range. 1402f61eb416SIlia Diachkov bool IsConstantIndex = 1403f61eb416SIlia Diachkov IndexInstruction->getOpcode() == TargetOpcode::G_CONSTANT; 1404f61eb416SIlia Diachkov 1405f61eb416SIlia Diachkov // If it's out of range (max dimension is 3), we can just return the constant 1406f61eb416SIlia Diachkov // default value (0 or 1 depending on which query function). 1407f61eb416SIlia Diachkov if (IsConstantIndex && getIConstVal(IndexRegister, MRI) >= 3) { 140874c66710SIlia Diachkov Register DefaultReg = Call->ReturnRegister; 1409f61eb416SIlia Diachkov if (PointerSize != ResultWidth) { 141074c66710SIlia Diachkov DefaultReg = MRI->createGenericVirtualRegister(LLT::scalar(PointerSize)); 1411f9c98068SVyacheslav Levytskyy MRI->setRegClass(DefaultReg, &SPIRV::iIDRegClass); 141274c66710SIlia Diachkov GR->assignSPIRVTypeToVReg(PointerSizeType, DefaultReg, 1413f61eb416SIlia Diachkov MIRBuilder.getMF()); 141474c66710SIlia Diachkov ToTruncate = DefaultReg; 1415f61eb416SIlia Diachkov } 1416f61eb416SIlia Diachkov auto NewRegister = 1417f61eb416SIlia Diachkov GR->buildConstantInt(DefaultValue, MIRBuilder, PointerSizeType); 141874c66710SIlia Diachkov MIRBuilder.buildCopy(DefaultReg, NewRegister); 1419f61eb416SIlia Diachkov } else { // If it could be in range, we need to load from the given builtin. 1420f61eb416SIlia Diachkov auto Vec3Ty = 1421f61eb416SIlia Diachkov GR->getOrCreateSPIRVVectorType(PointerSizeType, 3, MIRBuilder); 1422f61eb416SIlia Diachkov Register LoadedVector = 1423f61eb416SIlia Diachkov buildBuiltinVariableLoad(MIRBuilder, Vec3Ty, GR, BuiltinValue, 1424f61eb416SIlia Diachkov LLT::fixed_vector(3, PointerSize)); 1425f61eb416SIlia Diachkov // Set up the vreg to extract the result to (possibly a new temporary one). 1426f61eb416SIlia Diachkov Register Extracted = Call->ReturnRegister; 1427f61eb416SIlia Diachkov if (!IsConstantIndex || PointerSize != ResultWidth) { 1428f61eb416SIlia Diachkov Extracted = MRI->createGenericVirtualRegister(LLT::scalar(PointerSize)); 1429f9c98068SVyacheslav Levytskyy MRI->setRegClass(Extracted, &SPIRV::iIDRegClass); 1430f61eb416SIlia Diachkov GR->assignSPIRVTypeToVReg(PointerSizeType, Extracted, MIRBuilder.getMF()); 1431f61eb416SIlia Diachkov } 1432f61eb416SIlia Diachkov // Use Intrinsic::spv_extractelt so dynamic vs static extraction is 1433f61eb416SIlia Diachkov // handled later: extr = spv_extractelt LoadedVector, IndexRegister. 1434f61eb416SIlia Diachkov MachineInstrBuilder ExtractInst = MIRBuilder.buildIntrinsic( 1435d9847cdeSSameer Sahasrabuddhe Intrinsic::spv_extractelt, ArrayRef<Register>{Extracted}, true, false); 1436f61eb416SIlia Diachkov ExtractInst.addUse(LoadedVector).addUse(IndexRegister); 1437f61eb416SIlia Diachkov 1438f61eb416SIlia Diachkov // If the index is dynamic, need check if it's < 3, and then use a select. 1439f61eb416SIlia Diachkov if (!IsConstantIndex) { 1440f61eb416SIlia Diachkov insertAssignInstr(Extracted, nullptr, PointerSizeType, GR, MIRBuilder, 1441f61eb416SIlia Diachkov *MRI); 1442f61eb416SIlia Diachkov 1443f61eb416SIlia Diachkov auto IndexType = GR->getSPIRVTypeForVReg(IndexRegister); 1444f61eb416SIlia Diachkov auto BoolType = GR->getOrCreateSPIRVBoolType(MIRBuilder); 1445f61eb416SIlia Diachkov 1446f61eb416SIlia Diachkov Register CompareRegister = 1447f61eb416SIlia Diachkov MRI->createGenericVirtualRegister(LLT::scalar(1)); 1448f9c98068SVyacheslav Levytskyy MRI->setRegClass(CompareRegister, &SPIRV::iIDRegClass); 1449f61eb416SIlia Diachkov GR->assignSPIRVTypeToVReg(BoolType, CompareRegister, MIRBuilder.getMF()); 1450f61eb416SIlia Diachkov 1451f61eb416SIlia Diachkov // Use G_ICMP to check if idxVReg < 3. 1452f61eb416SIlia Diachkov MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CompareRegister, IndexRegister, 1453f61eb416SIlia Diachkov GR->buildConstantInt(3, MIRBuilder, IndexType)); 1454f61eb416SIlia Diachkov 1455f61eb416SIlia Diachkov // Get constant for the default value (0 or 1 depending on which 1456f61eb416SIlia Diachkov // function). 1457f61eb416SIlia Diachkov Register DefaultRegister = 1458f61eb416SIlia Diachkov GR->buildConstantInt(DefaultValue, MIRBuilder, PointerSizeType); 1459f61eb416SIlia Diachkov 1460f61eb416SIlia Diachkov // Get a register for the selection result (possibly a new temporary one). 1461f61eb416SIlia Diachkov Register SelectionResult = Call->ReturnRegister; 1462f61eb416SIlia Diachkov if (PointerSize != ResultWidth) { 1463f61eb416SIlia Diachkov SelectionResult = 1464f61eb416SIlia Diachkov MRI->createGenericVirtualRegister(LLT::scalar(PointerSize)); 1465f9c98068SVyacheslav Levytskyy MRI->setRegClass(SelectionResult, &SPIRV::iIDRegClass); 1466f61eb416SIlia Diachkov GR->assignSPIRVTypeToVReg(PointerSizeType, SelectionResult, 1467f61eb416SIlia Diachkov MIRBuilder.getMF()); 1468f61eb416SIlia Diachkov } 1469f61eb416SIlia Diachkov // Create the final G_SELECT to return the extracted value or the default. 1470f61eb416SIlia Diachkov MIRBuilder.buildSelect(SelectionResult, CompareRegister, Extracted, 1471f61eb416SIlia Diachkov DefaultRegister); 1472f61eb416SIlia Diachkov ToTruncate = SelectionResult; 1473f61eb416SIlia Diachkov } else { 1474f61eb416SIlia Diachkov ToTruncate = Extracted; 1475f61eb416SIlia Diachkov } 1476f61eb416SIlia Diachkov } 1477f61eb416SIlia Diachkov // Alter the result's bitwidth if it does not match the SizeT value extracted. 1478f61eb416SIlia Diachkov if (PointerSize != ResultWidth) 1479f61eb416SIlia Diachkov MIRBuilder.buildZExtOrTrunc(Call->ReturnRegister, ToTruncate); 1480f61eb416SIlia Diachkov return true; 1481f61eb416SIlia Diachkov } 1482f61eb416SIlia Diachkov 1483f61eb416SIlia Diachkov static bool generateBuiltinVar(const SPIRV::IncomingCall *Call, 1484f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 1485f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 1486f61eb416SIlia Diachkov // Lookup the builtin variable record. 1487f61eb416SIlia Diachkov const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 1488f61eb416SIlia Diachkov SPIRV::BuiltIn::BuiltIn Value = 1489f61eb416SIlia Diachkov SPIRV::lookupGetBuiltin(Builtin->Name, Builtin->Set)->Value; 1490f61eb416SIlia Diachkov 1491f61eb416SIlia Diachkov if (Value == SPIRV::BuiltIn::GlobalInvocationId) 1492f61eb416SIlia Diachkov return genWorkgroupQuery(Call, MIRBuilder, GR, Value, 0); 1493f61eb416SIlia Diachkov 1494f61eb416SIlia Diachkov // Build a load instruction for the builtin variable. 1495f61eb416SIlia Diachkov unsigned BitWidth = GR->getScalarOrVectorBitWidth(Call->ReturnType); 1496f61eb416SIlia Diachkov LLT LLType; 1497f61eb416SIlia Diachkov if (Call->ReturnType->getOpcode() == SPIRV::OpTypeVector) 1498f61eb416SIlia Diachkov LLType = 1499f61eb416SIlia Diachkov LLT::fixed_vector(Call->ReturnType->getOperand(2).getImm(), BitWidth); 1500f61eb416SIlia Diachkov else 1501f61eb416SIlia Diachkov LLType = LLT::scalar(BitWidth); 1502f61eb416SIlia Diachkov 1503f61eb416SIlia Diachkov return buildBuiltinVariableLoad(MIRBuilder, Call->ReturnType, GR, Value, 1504f61eb416SIlia Diachkov LLType, Call->ReturnRegister); 1505f61eb416SIlia Diachkov } 1506f61eb416SIlia Diachkov 1507f61eb416SIlia Diachkov static bool generateAtomicInst(const SPIRV::IncomingCall *Call, 1508f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 1509f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 1510f61eb416SIlia Diachkov // Lookup the instruction opcode in the TableGen records. 1511f61eb416SIlia Diachkov const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 1512f61eb416SIlia Diachkov unsigned Opcode = 1513f61eb416SIlia Diachkov SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode; 1514f61eb416SIlia Diachkov 1515f61eb416SIlia Diachkov switch (Opcode) { 15165fb4a051SMichal Paszkowski case SPIRV::OpStore: 15175fb4a051SMichal Paszkowski return buildAtomicInitInst(Call, MIRBuilder); 1518f61eb416SIlia Diachkov case SPIRV::OpAtomicLoad: 1519f61eb416SIlia Diachkov return buildAtomicLoadInst(Call, MIRBuilder, GR); 1520f61eb416SIlia Diachkov case SPIRV::OpAtomicStore: 1521f61eb416SIlia Diachkov return buildAtomicStoreInst(Call, MIRBuilder, GR); 1522f61eb416SIlia Diachkov case SPIRV::OpAtomicCompareExchange: 1523f61eb416SIlia Diachkov case SPIRV::OpAtomicCompareExchangeWeak: 1524c2483ed5SVyacheslav Levytskyy return buildAtomicCompareExchangeInst(Call, Builtin, Opcode, MIRBuilder, 1525c2483ed5SVyacheslav Levytskyy GR); 1526f61eb416SIlia Diachkov case SPIRV::OpAtomicIAdd: 1527f61eb416SIlia Diachkov case SPIRV::OpAtomicISub: 1528f61eb416SIlia Diachkov case SPIRV::OpAtomicOr: 1529f61eb416SIlia Diachkov case SPIRV::OpAtomicXor: 1530f61eb416SIlia Diachkov case SPIRV::OpAtomicAnd: 15315fb4a051SMichal Paszkowski case SPIRV::OpAtomicExchange: 1532f61eb416SIlia Diachkov return buildAtomicRMWInst(Call, Opcode, MIRBuilder, GR); 1533f61eb416SIlia Diachkov case SPIRV::OpMemoryBarrier: 1534f61eb416SIlia Diachkov return buildBarrierInst(Call, SPIRV::OpMemoryBarrier, MIRBuilder, GR); 153587080898SMichal Paszkowski case SPIRV::OpAtomicFlagTestAndSet: 153687080898SMichal Paszkowski case SPIRV::OpAtomicFlagClear: 153787080898SMichal Paszkowski return buildAtomicFlagInst(Call, Opcode, MIRBuilder, GR); 1538f61eb416SIlia Diachkov default: 153924cee1c4SVyacheslav Levytskyy if (Call->isSpirvOp()) 154024cee1c4SVyacheslav Levytskyy return buildOpFromWrapper(MIRBuilder, Opcode, Call, 154124cee1c4SVyacheslav Levytskyy GR->getSPIRVTypeID(Call->ReturnType)); 1542f61eb416SIlia Diachkov return false; 1543f61eb416SIlia Diachkov } 1544f61eb416SIlia Diachkov } 1545f61eb416SIlia Diachkov 1546925768eeSVyacheslav Levytskyy static bool generateAtomicFloatingInst(const SPIRV::IncomingCall *Call, 1547925768eeSVyacheslav Levytskyy MachineIRBuilder &MIRBuilder, 1548925768eeSVyacheslav Levytskyy SPIRVGlobalRegistry *GR) { 1549925768eeSVyacheslav Levytskyy // Lookup the instruction opcode in the TableGen records. 1550925768eeSVyacheslav Levytskyy const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 1551925768eeSVyacheslav Levytskyy unsigned Opcode = SPIRV::lookupAtomicFloatingBuiltin(Builtin->Name)->Opcode; 1552925768eeSVyacheslav Levytskyy 1553925768eeSVyacheslav Levytskyy switch (Opcode) { 1554925768eeSVyacheslav Levytskyy case SPIRV::OpAtomicFAddEXT: 1555925768eeSVyacheslav Levytskyy case SPIRV::OpAtomicFMinEXT: 1556925768eeSVyacheslav Levytskyy case SPIRV::OpAtomicFMaxEXT: 1557925768eeSVyacheslav Levytskyy return buildAtomicFloatingRMWInst(Call, Opcode, MIRBuilder, GR); 1558925768eeSVyacheslav Levytskyy default: 1559925768eeSVyacheslav Levytskyy return false; 1560925768eeSVyacheslav Levytskyy } 1561925768eeSVyacheslav Levytskyy } 1562925768eeSVyacheslav Levytskyy 1563f61eb416SIlia Diachkov static bool generateBarrierInst(const SPIRV::IncomingCall *Call, 1564f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 1565f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 1566f61eb416SIlia Diachkov // Lookup the instruction opcode in the TableGen records. 1567f61eb416SIlia Diachkov const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 1568f61eb416SIlia Diachkov unsigned Opcode = 1569f61eb416SIlia Diachkov SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode; 1570f61eb416SIlia Diachkov 1571f61eb416SIlia Diachkov return buildBarrierInst(Call, Opcode, MIRBuilder, GR); 1572f61eb416SIlia Diachkov } 1573f61eb416SIlia Diachkov 157457520985SVyacheslav Levytskyy static bool generateCastToPtrInst(const SPIRV::IncomingCall *Call, 157557520985SVyacheslav Levytskyy MachineIRBuilder &MIRBuilder) { 157657520985SVyacheslav Levytskyy MIRBuilder.buildInstr(TargetOpcode::G_ADDRSPACE_CAST) 157757520985SVyacheslav Levytskyy .addDef(Call->ReturnRegister) 157857520985SVyacheslav Levytskyy .addUse(Call->Arguments[0]); 157957520985SVyacheslav Levytskyy return true; 158057520985SVyacheslav Levytskyy } 158157520985SVyacheslav Levytskyy 1582f61eb416SIlia Diachkov static bool generateDotOrFMulInst(const SPIRV::IncomingCall *Call, 1583f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 1584f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 158524cee1c4SVyacheslav Levytskyy if (Call->isSpirvOp()) 158624cee1c4SVyacheslav Levytskyy return buildOpFromWrapper(MIRBuilder, SPIRV::OpDot, Call, 158724cee1c4SVyacheslav Levytskyy GR->getSPIRVTypeID(Call->ReturnType)); 1588f61eb416SIlia Diachkov unsigned Opcode = GR->getSPIRVTypeForVReg(Call->Arguments[0])->getOpcode(); 1589f61eb416SIlia Diachkov bool IsVec = Opcode == SPIRV::OpTypeVector; 1590f61eb416SIlia Diachkov // Use OpDot only in case of vector args and OpFMul in case of scalar args. 1591f61eb416SIlia Diachkov MIRBuilder.buildInstr(IsVec ? SPIRV::OpDot : SPIRV::OpFMulS) 1592f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 1593f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(Call->ReturnType)) 1594f61eb416SIlia Diachkov .addUse(Call->Arguments[0]) 1595f61eb416SIlia Diachkov .addUse(Call->Arguments[1]); 1596f61eb416SIlia Diachkov return true; 1597f61eb416SIlia Diachkov } 1598f61eb416SIlia Diachkov 1599f0eb9083SNathan Gauër static bool generateWaveInst(const SPIRV::IncomingCall *Call, 1600f0eb9083SNathan Gauër MachineIRBuilder &MIRBuilder, 1601f0eb9083SNathan Gauër SPIRVGlobalRegistry *GR) { 1602f0eb9083SNathan Gauër const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 1603f0eb9083SNathan Gauër SPIRV::BuiltIn::BuiltIn Value = 1604f0eb9083SNathan Gauër SPIRV::lookupGetBuiltin(Builtin->Name, Builtin->Set)->Value; 1605f0eb9083SNathan Gauër 1606f0eb9083SNathan Gauër // For now, we only support a single Wave intrinsic with a single return type. 1607f0eb9083SNathan Gauër assert(Call->ReturnType->getOpcode() == SPIRV::OpTypeInt); 1608f0eb9083SNathan Gauër LLT LLType = LLT::scalar(GR->getScalarOrVectorBitWidth(Call->ReturnType)); 1609f0eb9083SNathan Gauër 1610f0eb9083SNathan Gauër return buildBuiltinVariableLoad( 1611f0eb9083SNathan Gauër MIRBuilder, Call->ReturnType, GR, Value, LLType, Call->ReturnRegister, 1612f0eb9083SNathan Gauër /* isConst= */ false, /* hasLinkageTy= */ false); 1613f0eb9083SNathan Gauër } 1614f0eb9083SNathan Gauër 16158ac46d6bSVyacheslav Levytskyy // We expect a builtin 16168ac46d6bSVyacheslav Levytskyy // Name(ptr sret([RetType]) %result, Type %operand1, Type %operand1) 16178ac46d6bSVyacheslav Levytskyy // where %result is a pointer to where the result of the builtin execution 16188ac46d6bSVyacheslav Levytskyy // is to be stored, and generate the following instructions: 16198ac46d6bSVyacheslav Levytskyy // Res = Opcode RetType Operand1 Operand1 16208ac46d6bSVyacheslav Levytskyy // OpStore RetVariable Res 16218ac46d6bSVyacheslav Levytskyy static bool generateICarryBorrowInst(const SPIRV::IncomingCall *Call, 16228ac46d6bSVyacheslav Levytskyy MachineIRBuilder &MIRBuilder, 16238ac46d6bSVyacheslav Levytskyy SPIRVGlobalRegistry *GR) { 16248ac46d6bSVyacheslav Levytskyy const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 16258ac46d6bSVyacheslav Levytskyy unsigned Opcode = 16268ac46d6bSVyacheslav Levytskyy SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode; 16278ac46d6bSVyacheslav Levytskyy 16288ac46d6bSVyacheslav Levytskyy Register SRetReg = Call->Arguments[0]; 16298ac46d6bSVyacheslav Levytskyy SPIRVType *PtrRetType = GR->getSPIRVTypeForVReg(SRetReg); 16308ac46d6bSVyacheslav Levytskyy SPIRVType *RetType = GR->getPointeeType(PtrRetType); 16318ac46d6bSVyacheslav Levytskyy if (!RetType) 16328ac46d6bSVyacheslav Levytskyy report_fatal_error("The first parameter must be a pointer"); 16338ac46d6bSVyacheslav Levytskyy if (RetType->getOpcode() != SPIRV::OpTypeStruct) 16348ac46d6bSVyacheslav Levytskyy report_fatal_error("Expected struct type result for the arithmetic with " 16358ac46d6bSVyacheslav Levytskyy "overflow builtins"); 16368ac46d6bSVyacheslav Levytskyy 16378ac46d6bSVyacheslav Levytskyy SPIRVType *OpType1 = GR->getSPIRVTypeForVReg(Call->Arguments[1]); 16388ac46d6bSVyacheslav Levytskyy SPIRVType *OpType2 = GR->getSPIRVTypeForVReg(Call->Arguments[2]); 16398ac46d6bSVyacheslav Levytskyy if (!OpType1 || !OpType2 || OpType1 != OpType2) 16408ac46d6bSVyacheslav Levytskyy report_fatal_error("Operands must have the same type"); 16418ac46d6bSVyacheslav Levytskyy if (OpType1->getOpcode() == SPIRV::OpTypeVector) 16428ac46d6bSVyacheslav Levytskyy switch (Opcode) { 16438ac46d6bSVyacheslav Levytskyy case SPIRV::OpIAddCarryS: 16448ac46d6bSVyacheslav Levytskyy Opcode = SPIRV::OpIAddCarryV; 16458ac46d6bSVyacheslav Levytskyy break; 16468ac46d6bSVyacheslav Levytskyy case SPIRV::OpISubBorrowS: 16478ac46d6bSVyacheslav Levytskyy Opcode = SPIRV::OpISubBorrowV; 16488ac46d6bSVyacheslav Levytskyy break; 16498ac46d6bSVyacheslav Levytskyy } 16508ac46d6bSVyacheslav Levytskyy 16518ac46d6bSVyacheslav Levytskyy MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 165242633cf2SVyacheslav Levytskyy Register ResReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass); 165342633cf2SVyacheslav Levytskyy if (const TargetRegisterClass *DstRC = 165442633cf2SVyacheslav Levytskyy MRI->getRegClassOrNull(Call->Arguments[1])) { 165542633cf2SVyacheslav Levytskyy MRI->setRegClass(ResReg, DstRC); 165642633cf2SVyacheslav Levytskyy MRI->setType(ResReg, MRI->getType(Call->Arguments[1])); 165742633cf2SVyacheslav Levytskyy } else { 165842633cf2SVyacheslav Levytskyy MRI->setType(ResReg, LLT::scalar(64)); 165942633cf2SVyacheslav Levytskyy } 16608ac46d6bSVyacheslav Levytskyy GR->assignSPIRVTypeToVReg(RetType, ResReg, MIRBuilder.getMF()); 16618ac46d6bSVyacheslav Levytskyy MIRBuilder.buildInstr(Opcode) 16628ac46d6bSVyacheslav Levytskyy .addDef(ResReg) 16638ac46d6bSVyacheslav Levytskyy .addUse(GR->getSPIRVTypeID(RetType)) 16648ac46d6bSVyacheslav Levytskyy .addUse(Call->Arguments[1]) 16658ac46d6bSVyacheslav Levytskyy .addUse(Call->Arguments[2]); 16668ac46d6bSVyacheslav Levytskyy MIRBuilder.buildInstr(SPIRV::OpStore).addUse(SRetReg).addUse(ResReg); 16678ac46d6bSVyacheslav Levytskyy return true; 16688ac46d6bSVyacheslav Levytskyy } 16698ac46d6bSVyacheslav Levytskyy 1670f61eb416SIlia Diachkov static bool generateGetQueryInst(const SPIRV::IncomingCall *Call, 1671f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 1672f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 1673f61eb416SIlia Diachkov // Lookup the builtin record. 1674f61eb416SIlia Diachkov SPIRV::BuiltIn::BuiltIn Value = 1675f61eb416SIlia Diachkov SPIRV::lookupGetBuiltin(Call->Builtin->Name, Call->Builtin->Set)->Value; 1676f61eb416SIlia Diachkov uint64_t IsDefault = (Value == SPIRV::BuiltIn::GlobalSize || 1677f61eb416SIlia Diachkov Value == SPIRV::BuiltIn::WorkgroupSize || 1678f61eb416SIlia Diachkov Value == SPIRV::BuiltIn::EnqueuedWorkgroupSize); 1679f61eb416SIlia Diachkov return genWorkgroupQuery(Call, MIRBuilder, GR, Value, IsDefault ? 1 : 0); 1680f61eb416SIlia Diachkov } 1681f61eb416SIlia Diachkov 1682f61eb416SIlia Diachkov static bool generateImageSizeQueryInst(const SPIRV::IncomingCall *Call, 1683f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 1684f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 1685f61eb416SIlia Diachkov // Lookup the image size query component number in the TableGen records. 1686f61eb416SIlia Diachkov const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 1687f61eb416SIlia Diachkov uint32_t Component = 1688f61eb416SIlia Diachkov SPIRV::lookupImageQueryBuiltin(Builtin->Name, Builtin->Set)->Component; 1689f61eb416SIlia Diachkov // Query result may either be a vector or a scalar. If return type is not a 1690f61eb416SIlia Diachkov // vector, expect only a single size component. Otherwise get the number of 1691f61eb416SIlia Diachkov // expected components. 1692f61eb416SIlia Diachkov SPIRVType *RetTy = Call->ReturnType; 1693f61eb416SIlia Diachkov unsigned NumExpectedRetComponents = RetTy->getOpcode() == SPIRV::OpTypeVector 1694f61eb416SIlia Diachkov ? RetTy->getOperand(2).getImm() 1695f61eb416SIlia Diachkov : 1; 1696f61eb416SIlia Diachkov // Get the actual number of query result/size components. 1697f61eb416SIlia Diachkov SPIRVType *ImgType = GR->getSPIRVTypeForVReg(Call->Arguments[0]); 1698f61eb416SIlia Diachkov unsigned NumActualRetComponents = getNumSizeComponents(ImgType); 1699f61eb416SIlia Diachkov Register QueryResult = Call->ReturnRegister; 1700f61eb416SIlia Diachkov SPIRVType *QueryResultType = Call->ReturnType; 1701f61eb416SIlia Diachkov if (NumExpectedRetComponents != NumActualRetComponents) { 1702f61eb416SIlia Diachkov QueryResult = MIRBuilder.getMRI()->createGenericVirtualRegister( 1703f61eb416SIlia Diachkov LLT::fixed_vector(NumActualRetComponents, 32)); 170467d3ef74SVyacheslav Levytskyy MIRBuilder.getMRI()->setRegClass(QueryResult, &SPIRV::vIDRegClass); 1705f61eb416SIlia Diachkov SPIRVType *IntTy = GR->getOrCreateSPIRVIntegerType(32, MIRBuilder); 1706f61eb416SIlia Diachkov QueryResultType = GR->getOrCreateSPIRVVectorType( 1707f61eb416SIlia Diachkov IntTy, NumActualRetComponents, MIRBuilder); 1708f61eb416SIlia Diachkov GR->assignSPIRVTypeToVReg(QueryResultType, QueryResult, MIRBuilder.getMF()); 1709f61eb416SIlia Diachkov } 1710f61eb416SIlia Diachkov bool IsDimBuf = ImgType->getOperand(2).getImm() == SPIRV::Dim::DIM_Buffer; 1711f61eb416SIlia Diachkov unsigned Opcode = 1712f61eb416SIlia Diachkov IsDimBuf ? SPIRV::OpImageQuerySize : SPIRV::OpImageQuerySizeLod; 1713f61eb416SIlia Diachkov auto MIB = MIRBuilder.buildInstr(Opcode) 1714f61eb416SIlia Diachkov .addDef(QueryResult) 1715f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(QueryResultType)) 1716f61eb416SIlia Diachkov .addUse(Call->Arguments[0]); 1717f61eb416SIlia Diachkov if (!IsDimBuf) 171867d3ef74SVyacheslav Levytskyy MIB.addUse(buildConstantIntReg32(0, MIRBuilder, GR)); // Lod id. 1719f61eb416SIlia Diachkov if (NumExpectedRetComponents == NumActualRetComponents) 1720f61eb416SIlia Diachkov return true; 1721f61eb416SIlia Diachkov if (NumExpectedRetComponents == 1) { 1722f61eb416SIlia Diachkov // Only 1 component is expected, build OpCompositeExtract instruction. 1723f61eb416SIlia Diachkov unsigned ExtractedComposite = 1724f61eb416SIlia Diachkov Component == 3 ? NumActualRetComponents - 1 : Component; 1725f61eb416SIlia Diachkov assert(ExtractedComposite < NumActualRetComponents && 1726f61eb416SIlia Diachkov "Invalid composite index!"); 1727505cd125SVyacheslav Levytskyy Register TypeReg = GR->getSPIRVTypeID(Call->ReturnType); 1728505cd125SVyacheslav Levytskyy SPIRVType *NewType = nullptr; 1729505cd125SVyacheslav Levytskyy if (QueryResultType->getOpcode() == SPIRV::OpTypeVector) { 1730505cd125SVyacheslav Levytskyy Register NewTypeReg = QueryResultType->getOperand(1).getReg(); 1731505cd125SVyacheslav Levytskyy if (TypeReg != NewTypeReg && 1732505cd125SVyacheslav Levytskyy (NewType = GR->getSPIRVTypeForVReg(NewTypeReg)) != nullptr) 1733505cd125SVyacheslav Levytskyy TypeReg = NewTypeReg; 1734505cd125SVyacheslav Levytskyy } 1735f61eb416SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpCompositeExtract) 1736f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 1737505cd125SVyacheslav Levytskyy .addUse(TypeReg) 1738f61eb416SIlia Diachkov .addUse(QueryResult) 1739f61eb416SIlia Diachkov .addImm(ExtractedComposite); 1740505cd125SVyacheslav Levytskyy if (NewType != nullptr) 1741505cd125SVyacheslav Levytskyy insertAssignInstr(Call->ReturnRegister, nullptr, NewType, GR, MIRBuilder, 1742505cd125SVyacheslav Levytskyy MIRBuilder.getMF().getRegInfo()); 1743f61eb416SIlia Diachkov } else { 1744f61eb416SIlia Diachkov // More than 1 component is expected, fill a new vector. 1745f61eb416SIlia Diachkov auto MIB = MIRBuilder.buildInstr(SPIRV::OpVectorShuffle) 1746f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 1747f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(Call->ReturnType)) 1748f61eb416SIlia Diachkov .addUse(QueryResult) 1749f61eb416SIlia Diachkov .addUse(QueryResult); 1750f61eb416SIlia Diachkov for (unsigned i = 0; i < NumExpectedRetComponents; ++i) 1751f61eb416SIlia Diachkov MIB.addImm(i < NumActualRetComponents ? i : 0xffffffff); 1752f61eb416SIlia Diachkov } 1753f61eb416SIlia Diachkov return true; 1754f61eb416SIlia Diachkov } 1755f61eb416SIlia Diachkov 1756f61eb416SIlia Diachkov static bool generateImageMiscQueryInst(const SPIRV::IncomingCall *Call, 1757f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 1758f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 1759f61eb416SIlia Diachkov assert(Call->ReturnType->getOpcode() == SPIRV::OpTypeInt && 1760f61eb416SIlia Diachkov "Image samples query result must be of int type!"); 17616beac40fSMichal Paszkowski 17626beac40fSMichal Paszkowski // Lookup the instruction opcode in the TableGen records. 17636beac40fSMichal Paszkowski const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 17646beac40fSMichal Paszkowski unsigned Opcode = 17656beac40fSMichal Paszkowski SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode; 17666beac40fSMichal Paszkowski 17676beac40fSMichal Paszkowski Register Image = Call->Arguments[0]; 17686beac40fSMichal Paszkowski SPIRV::Dim::Dim ImageDimensionality = static_cast<SPIRV::Dim::Dim>( 17696beac40fSMichal Paszkowski GR->getSPIRVTypeForVReg(Image)->getOperand(2).getImm()); 1770b221b973SVyacheslav Levytskyy (void)ImageDimensionality; 17716beac40fSMichal Paszkowski 17726beac40fSMichal Paszkowski switch (Opcode) { 17736beac40fSMichal Paszkowski case SPIRV::OpImageQuerySamples: 17746beac40fSMichal Paszkowski assert(ImageDimensionality == SPIRV::Dim::DIM_2D && 1775f61eb416SIlia Diachkov "Image must be of 2D dimensionality"); 17766beac40fSMichal Paszkowski break; 17776beac40fSMichal Paszkowski case SPIRV::OpImageQueryLevels: 17786beac40fSMichal Paszkowski assert((ImageDimensionality == SPIRV::Dim::DIM_1D || 17796beac40fSMichal Paszkowski ImageDimensionality == SPIRV::Dim::DIM_2D || 17806beac40fSMichal Paszkowski ImageDimensionality == SPIRV::Dim::DIM_3D || 17816beac40fSMichal Paszkowski ImageDimensionality == SPIRV::Dim::DIM_Cube) && 17826beac40fSMichal Paszkowski "Image must be of 1D/2D/3D/Cube dimensionality"); 17836beac40fSMichal Paszkowski break; 17846beac40fSMichal Paszkowski } 17856beac40fSMichal Paszkowski 17866beac40fSMichal Paszkowski MIRBuilder.buildInstr(Opcode) 1787f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 1788f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(Call->ReturnType)) 1789f61eb416SIlia Diachkov .addUse(Image); 1790f61eb416SIlia Diachkov return true; 1791f61eb416SIlia Diachkov } 1792f61eb416SIlia Diachkov 1793f61eb416SIlia Diachkov // TODO: Move to TableGen. 1794f61eb416SIlia Diachkov static SPIRV::SamplerAddressingMode::SamplerAddressingMode 1795f61eb416SIlia Diachkov getSamplerAddressingModeFromBitmask(unsigned Bitmask) { 1796f61eb416SIlia Diachkov switch (Bitmask & SPIRV::CLK_ADDRESS_MODE_MASK) { 1797f61eb416SIlia Diachkov case SPIRV::CLK_ADDRESS_CLAMP: 1798f61eb416SIlia Diachkov return SPIRV::SamplerAddressingMode::Clamp; 1799f61eb416SIlia Diachkov case SPIRV::CLK_ADDRESS_CLAMP_TO_EDGE: 1800f61eb416SIlia Diachkov return SPIRV::SamplerAddressingMode::ClampToEdge; 1801f61eb416SIlia Diachkov case SPIRV::CLK_ADDRESS_REPEAT: 1802f61eb416SIlia Diachkov return SPIRV::SamplerAddressingMode::Repeat; 1803f61eb416SIlia Diachkov case SPIRV::CLK_ADDRESS_MIRRORED_REPEAT: 1804f61eb416SIlia Diachkov return SPIRV::SamplerAddressingMode::RepeatMirrored; 1805f61eb416SIlia Diachkov case SPIRV::CLK_ADDRESS_NONE: 1806f61eb416SIlia Diachkov return SPIRV::SamplerAddressingMode::None; 1807f61eb416SIlia Diachkov default: 1808925768eeSVyacheslav Levytskyy report_fatal_error("Unknown CL address mode"); 1809f61eb416SIlia Diachkov } 1810f61eb416SIlia Diachkov } 1811f61eb416SIlia Diachkov 1812f61eb416SIlia Diachkov static unsigned getSamplerParamFromBitmask(unsigned Bitmask) { 1813f61eb416SIlia Diachkov return (Bitmask & SPIRV::CLK_NORMALIZED_COORDS_TRUE) ? 1 : 0; 1814f61eb416SIlia Diachkov } 1815f61eb416SIlia Diachkov 1816f61eb416SIlia Diachkov static SPIRV::SamplerFilterMode::SamplerFilterMode 1817f61eb416SIlia Diachkov getSamplerFilterModeFromBitmask(unsigned Bitmask) { 1818f61eb416SIlia Diachkov if (Bitmask & SPIRV::CLK_FILTER_LINEAR) 1819f61eb416SIlia Diachkov return SPIRV::SamplerFilterMode::Linear; 1820f61eb416SIlia Diachkov if (Bitmask & SPIRV::CLK_FILTER_NEAREST) 1821f61eb416SIlia Diachkov return SPIRV::SamplerFilterMode::Nearest; 1822f61eb416SIlia Diachkov return SPIRV::SamplerFilterMode::Nearest; 1823f61eb416SIlia Diachkov } 1824f61eb416SIlia Diachkov 1825f61eb416SIlia Diachkov static bool generateReadImageInst(const StringRef DemangledCall, 1826f61eb416SIlia Diachkov const SPIRV::IncomingCall *Call, 1827f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 1828f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 1829f61eb416SIlia Diachkov Register Image = Call->Arguments[0]; 1830f61eb416SIlia Diachkov MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 183174c66710SIlia Diachkov bool HasOclSampler = DemangledCall.contains_insensitive("ocl_sampler"); 183274c66710SIlia Diachkov bool HasMsaa = DemangledCall.contains_insensitive("msaa"); 183374c66710SIlia Diachkov if (HasOclSampler) { 1834f61eb416SIlia Diachkov Register Sampler = Call->Arguments[1]; 1835f61eb416SIlia Diachkov 1836f61eb416SIlia Diachkov if (!GR->isScalarOfType(Sampler, SPIRV::OpTypeSampler) && 1837f61eb416SIlia Diachkov getDefInstrMaybeConstant(Sampler, MRI)->getOperand(1).isCImm()) { 1838f61eb416SIlia Diachkov uint64_t SamplerMask = getIConstVal(Sampler, MRI); 1839f61eb416SIlia Diachkov Sampler = GR->buildConstantSampler( 1840f61eb416SIlia Diachkov Register(), getSamplerAddressingModeFromBitmask(SamplerMask), 1841f61eb416SIlia Diachkov getSamplerParamFromBitmask(SamplerMask), 1842f61eb416SIlia Diachkov getSamplerFilterModeFromBitmask(SamplerMask), MIRBuilder, 1843f61eb416SIlia Diachkov GR->getSPIRVTypeForVReg(Sampler)); 1844f61eb416SIlia Diachkov } 1845f61eb416SIlia Diachkov SPIRVType *ImageType = GR->getSPIRVTypeForVReg(Image); 1846f61eb416SIlia Diachkov SPIRVType *SampledImageType = 1847f61eb416SIlia Diachkov GR->getOrCreateOpTypeSampledImage(ImageType, MIRBuilder); 1848f9c98068SVyacheslav Levytskyy Register SampledImage = MRI->createVirtualRegister(&SPIRV::iIDRegClass); 1849f61eb416SIlia Diachkov 1850f61eb416SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpSampledImage) 1851f61eb416SIlia Diachkov .addDef(SampledImage) 1852f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(SampledImageType)) 1853f61eb416SIlia Diachkov .addUse(Image) 1854f61eb416SIlia Diachkov .addUse(Sampler); 1855f61eb416SIlia Diachkov 1856f61eb416SIlia Diachkov Register Lod = GR->buildConstantFP(APFloat::getZero(APFloat::IEEEsingle()), 1857f61eb416SIlia Diachkov MIRBuilder); 1858f61eb416SIlia Diachkov 185967d3ef74SVyacheslav Levytskyy if (Call->ReturnType->getOpcode() != SPIRV::OpTypeVector) { 186067d3ef74SVyacheslav Levytskyy SPIRVType *TempType = 186167d3ef74SVyacheslav Levytskyy GR->getOrCreateSPIRVVectorType(Call->ReturnType, 4, MIRBuilder); 186267d3ef74SVyacheslav Levytskyy Register TempRegister = 186367d3ef74SVyacheslav Levytskyy MRI->createGenericVirtualRegister(GR->getRegType(TempType)); 186467d3ef74SVyacheslav Levytskyy MRI->setRegClass(TempRegister, GR->getRegClass(TempType)); 186567d3ef74SVyacheslav Levytskyy GR->assignSPIRVTypeToVReg(TempType, TempRegister, MIRBuilder.getMF()); 1866f61eb416SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpImageSampleExplicitLod) 186767d3ef74SVyacheslav Levytskyy .addDef(TempRegister) 1868f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(TempType)) 1869f61eb416SIlia Diachkov .addUse(SampledImage) 1870f61eb416SIlia Diachkov .addUse(Call->Arguments[2]) // Coordinate. 1871f61eb416SIlia Diachkov .addImm(SPIRV::ImageOperand::Lod) 1872f61eb416SIlia Diachkov .addUse(Lod); 1873f61eb416SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpCompositeExtract) 1874f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 1875f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(Call->ReturnType)) 1876f61eb416SIlia Diachkov .addUse(TempRegister) 1877f61eb416SIlia Diachkov .addImm(0); 187867d3ef74SVyacheslav Levytskyy } else { 187967d3ef74SVyacheslav Levytskyy MIRBuilder.buildInstr(SPIRV::OpImageSampleExplicitLod) 188067d3ef74SVyacheslav Levytskyy .addDef(Call->ReturnRegister) 188167d3ef74SVyacheslav Levytskyy .addUse(GR->getSPIRVTypeID(Call->ReturnType)) 188267d3ef74SVyacheslav Levytskyy .addUse(SampledImage) 188367d3ef74SVyacheslav Levytskyy .addUse(Call->Arguments[2]) // Coordinate. 188467d3ef74SVyacheslav Levytskyy .addImm(SPIRV::ImageOperand::Lod) 188567d3ef74SVyacheslav Levytskyy .addUse(Lod); 188667d3ef74SVyacheslav Levytskyy } 188774c66710SIlia Diachkov } else if (HasMsaa) { 1888f61eb416SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpImageRead) 1889f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 1890f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(Call->ReturnType)) 1891f61eb416SIlia Diachkov .addUse(Image) 1892f61eb416SIlia Diachkov .addUse(Call->Arguments[1]) // Coordinate. 1893f61eb416SIlia Diachkov .addImm(SPIRV::ImageOperand::Sample) 1894f61eb416SIlia Diachkov .addUse(Call->Arguments[2]); 1895f61eb416SIlia Diachkov } else { 1896f61eb416SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpImageRead) 1897f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 1898f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(Call->ReturnType)) 1899f61eb416SIlia Diachkov .addUse(Image) 1900f61eb416SIlia Diachkov .addUse(Call->Arguments[1]); // Coordinate. 1901f61eb416SIlia Diachkov } 1902f61eb416SIlia Diachkov return true; 1903f61eb416SIlia Diachkov } 1904f61eb416SIlia Diachkov 1905f61eb416SIlia Diachkov static bool generateWriteImageInst(const SPIRV::IncomingCall *Call, 1906f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 1907f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 1908f61eb416SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpImageWrite) 1909f61eb416SIlia Diachkov .addUse(Call->Arguments[0]) // Image. 1910f61eb416SIlia Diachkov .addUse(Call->Arguments[1]) // Coordinate. 1911f61eb416SIlia Diachkov .addUse(Call->Arguments[2]); // Texel. 1912f61eb416SIlia Diachkov return true; 1913f61eb416SIlia Diachkov } 1914f61eb416SIlia Diachkov 1915f61eb416SIlia Diachkov static bool generateSampleImageInst(const StringRef DemangledCall, 1916f61eb416SIlia Diachkov const SPIRV::IncomingCall *Call, 1917f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 1918f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 191974c66710SIlia Diachkov MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 1920f61eb416SIlia Diachkov if (Call->Builtin->Name.contains_insensitive( 1921f61eb416SIlia Diachkov "__translate_sampler_initializer")) { 1922f61eb416SIlia Diachkov // Build sampler literal. 192374c66710SIlia Diachkov uint64_t Bitmask = getIConstVal(Call->Arguments[0], MRI); 1924f61eb416SIlia Diachkov Register Sampler = GR->buildConstantSampler( 1925f61eb416SIlia Diachkov Call->ReturnRegister, getSamplerAddressingModeFromBitmask(Bitmask), 1926f61eb416SIlia Diachkov getSamplerParamFromBitmask(Bitmask), 1927f61eb416SIlia Diachkov getSamplerFilterModeFromBitmask(Bitmask), MIRBuilder, Call->ReturnType); 1928f61eb416SIlia Diachkov return Sampler.isValid(); 1929f61eb416SIlia Diachkov } else if (Call->Builtin->Name.contains_insensitive("__spirv_SampledImage")) { 1930f61eb416SIlia Diachkov // Create OpSampledImage. 1931f61eb416SIlia Diachkov Register Image = Call->Arguments[0]; 1932f61eb416SIlia Diachkov SPIRVType *ImageType = GR->getSPIRVTypeForVReg(Image); 1933f61eb416SIlia Diachkov SPIRVType *SampledImageType = 1934f61eb416SIlia Diachkov GR->getOrCreateOpTypeSampledImage(ImageType, MIRBuilder); 1935f61eb416SIlia Diachkov Register SampledImage = 1936f61eb416SIlia Diachkov Call->ReturnRegister.isValid() 1937f61eb416SIlia Diachkov ? Call->ReturnRegister 1938f9c98068SVyacheslav Levytskyy : MRI->createVirtualRegister(&SPIRV::iIDRegClass); 1939f61eb416SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpSampledImage) 1940f61eb416SIlia Diachkov .addDef(SampledImage) 1941f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(SampledImageType)) 1942f61eb416SIlia Diachkov .addUse(Image) 1943f61eb416SIlia Diachkov .addUse(Call->Arguments[1]); // Sampler. 1944f61eb416SIlia Diachkov return true; 1945f61eb416SIlia Diachkov } else if (Call->Builtin->Name.contains_insensitive( 1946f61eb416SIlia Diachkov "__spirv_ImageSampleExplicitLod")) { 1947f61eb416SIlia Diachkov // Sample an image using an explicit level of detail. 1948f61eb416SIlia Diachkov std::string ReturnType = DemangledCall.str(); 1949f61eb416SIlia Diachkov if (DemangledCall.contains("_R")) { 1950f61eb416SIlia Diachkov ReturnType = ReturnType.substr(ReturnType.find("_R") + 2); 1951f61eb416SIlia Diachkov ReturnType = ReturnType.substr(0, ReturnType.find('(')); 1952f61eb416SIlia Diachkov } 1953eb989f62SVyacheslav Levytskyy SPIRVType *Type = 1954eb989f62SVyacheslav Levytskyy Call->ReturnType 1955eb989f62SVyacheslav Levytskyy ? Call->ReturnType 1956eb989f62SVyacheslav Levytskyy : GR->getOrCreateSPIRVTypeByName(ReturnType, MIRBuilder); 19575a07774fSVyacheslav Levytskyy if (!Type) { 19585a07774fSVyacheslav Levytskyy std::string DiagMsg = 19595a07774fSVyacheslav Levytskyy "Unable to recognize SPIRV type name: " + ReturnType; 19605a07774fSVyacheslav Levytskyy report_fatal_error(DiagMsg.c_str()); 19615a07774fSVyacheslav Levytskyy } 1962f61eb416SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpImageSampleExplicitLod) 1963f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 1964f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(Type)) 1965f61eb416SIlia Diachkov .addUse(Call->Arguments[0]) // Image. 1966f61eb416SIlia Diachkov .addUse(Call->Arguments[1]) // Coordinate. 1967f61eb416SIlia Diachkov .addImm(SPIRV::ImageOperand::Lod) 1968f61eb416SIlia Diachkov .addUse(Call->Arguments[3]); 1969f61eb416SIlia Diachkov return true; 1970f61eb416SIlia Diachkov } 1971f61eb416SIlia Diachkov return false; 1972f61eb416SIlia Diachkov } 1973f61eb416SIlia Diachkov 1974f61eb416SIlia Diachkov static bool generateSelectInst(const SPIRV::IncomingCall *Call, 1975f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder) { 1976f61eb416SIlia Diachkov MIRBuilder.buildSelect(Call->ReturnRegister, Call->Arguments[0], 1977f61eb416SIlia Diachkov Call->Arguments[1], Call->Arguments[2]); 1978f61eb416SIlia Diachkov return true; 1979f61eb416SIlia Diachkov } 1980f61eb416SIlia Diachkov 198157f79371SVyacheslav Levytskyy static bool generateConstructInst(const SPIRV::IncomingCall *Call, 198257f79371SVyacheslav Levytskyy MachineIRBuilder &MIRBuilder, 198357f79371SVyacheslav Levytskyy SPIRVGlobalRegistry *GR) { 198457f79371SVyacheslav Levytskyy return buildOpFromWrapper(MIRBuilder, SPIRV::OpCompositeConstruct, Call, 198557f79371SVyacheslav Levytskyy GR->getSPIRVTypeID(Call->ReturnType)); 198657f79371SVyacheslav Levytskyy } 198757f79371SVyacheslav Levytskyy 198857f79371SVyacheslav Levytskyy static bool generateCoopMatrInst(const SPIRV::IncomingCall *Call, 198957f79371SVyacheslav Levytskyy MachineIRBuilder &MIRBuilder, 199057f79371SVyacheslav Levytskyy SPIRVGlobalRegistry *GR) { 199157f79371SVyacheslav Levytskyy const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 199257f79371SVyacheslav Levytskyy unsigned Opcode = 199357f79371SVyacheslav Levytskyy SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode; 1994d057b53aSDmitry Sidorov bool IsSet = Opcode != SPIRV::OpCooperativeMatrixStoreKHR && 1995d057b53aSDmitry Sidorov Opcode != SPIRV::OpCooperativeMatrixStoreCheckedINTEL && 1996d057b53aSDmitry Sidorov Opcode != SPIRV::OpCooperativeMatrixPrefetchINTEL; 199757f79371SVyacheslav Levytskyy unsigned ArgSz = Call->Arguments.size(); 199857f79371SVyacheslav Levytskyy unsigned LiteralIdx = 0; 1999d057b53aSDmitry Sidorov switch (Opcode) { 2000d057b53aSDmitry Sidorov // Memory operand is optional and is literal. 2001d057b53aSDmitry Sidorov case SPIRV::OpCooperativeMatrixLoadKHR: 2002d057b53aSDmitry Sidorov LiteralIdx = ArgSz > 3 ? 3 : 0; 2003d057b53aSDmitry Sidorov break; 2004d057b53aSDmitry Sidorov case SPIRV::OpCooperativeMatrixStoreKHR: 2005d057b53aSDmitry Sidorov LiteralIdx = ArgSz > 4 ? 4 : 0; 2006d057b53aSDmitry Sidorov break; 2007d057b53aSDmitry Sidorov case SPIRV::OpCooperativeMatrixLoadCheckedINTEL: 2008d057b53aSDmitry Sidorov LiteralIdx = ArgSz > 7 ? 7 : 0; 2009d057b53aSDmitry Sidorov break; 2010d057b53aSDmitry Sidorov case SPIRV::OpCooperativeMatrixStoreCheckedINTEL: 2011d057b53aSDmitry Sidorov LiteralIdx = ArgSz > 8 ? 8 : 0; 2012d057b53aSDmitry Sidorov break; 2013d057b53aSDmitry Sidorov // Cooperative Matrix Operands operand is optional and is literal. 2014d057b53aSDmitry Sidorov case SPIRV::OpCooperativeMatrixMulAddKHR: 2015d057b53aSDmitry Sidorov LiteralIdx = ArgSz > 3 ? 3 : 0; 2016d057b53aSDmitry Sidorov break; 2017d057b53aSDmitry Sidorov }; 2018d057b53aSDmitry Sidorov 201957f79371SVyacheslav Levytskyy SmallVector<uint32_t, 1> ImmArgs; 202057f79371SVyacheslav Levytskyy MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 2021d057b53aSDmitry Sidorov if (Opcode == SPIRV::OpCooperativeMatrixPrefetchINTEL) { 2022d057b53aSDmitry Sidorov const uint32_t CacheLevel = getConstFromIntrinsic(Call->Arguments[3], MRI); 2023d057b53aSDmitry Sidorov auto MIB = MIRBuilder.buildInstr(SPIRV::OpCooperativeMatrixPrefetchINTEL) 2024d057b53aSDmitry Sidorov .addUse(Call->Arguments[0]) // pointer 2025d057b53aSDmitry Sidorov .addUse(Call->Arguments[1]) // rows 2026d057b53aSDmitry Sidorov .addUse(Call->Arguments[2]) // columns 2027d057b53aSDmitry Sidorov .addImm(CacheLevel) // cache level 2028d057b53aSDmitry Sidorov .addUse(Call->Arguments[4]); // memory layout 2029d057b53aSDmitry Sidorov if (ArgSz > 5) 2030d057b53aSDmitry Sidorov MIB.addUse(Call->Arguments[5]); // stride 2031d057b53aSDmitry Sidorov if (ArgSz > 6) { 2032d057b53aSDmitry Sidorov const uint32_t MemOp = getConstFromIntrinsic(Call->Arguments[6], MRI); 2033d057b53aSDmitry Sidorov MIB.addImm(MemOp); // memory operand 2034d057b53aSDmitry Sidorov } 2035d057b53aSDmitry Sidorov return true; 2036d057b53aSDmitry Sidorov } 203757f79371SVyacheslav Levytskyy if (LiteralIdx > 0) 203857f79371SVyacheslav Levytskyy ImmArgs.push_back(getConstFromIntrinsic(Call->Arguments[LiteralIdx], MRI)); 203957f79371SVyacheslav Levytskyy Register TypeReg = GR->getSPIRVTypeID(Call->ReturnType); 204057f79371SVyacheslav Levytskyy if (Opcode == SPIRV::OpCooperativeMatrixLengthKHR) { 204157f79371SVyacheslav Levytskyy SPIRVType *CoopMatrType = GR->getSPIRVTypeForVReg(Call->Arguments[0]); 204257f79371SVyacheslav Levytskyy if (!CoopMatrType) 204357f79371SVyacheslav Levytskyy report_fatal_error("Can't find a register's type definition"); 204457f79371SVyacheslav Levytskyy MIRBuilder.buildInstr(Opcode) 204557f79371SVyacheslav Levytskyy .addDef(Call->ReturnRegister) 204657f79371SVyacheslav Levytskyy .addUse(TypeReg) 204757f79371SVyacheslav Levytskyy .addUse(CoopMatrType->getOperand(0).getReg()); 204857f79371SVyacheslav Levytskyy return true; 204957f79371SVyacheslav Levytskyy } 205057f79371SVyacheslav Levytskyy return buildOpFromWrapper(MIRBuilder, Opcode, Call, 205157f79371SVyacheslav Levytskyy IsSet ? TypeReg : Register(0), ImmArgs); 205257f79371SVyacheslav Levytskyy } 205357f79371SVyacheslav Levytskyy 2054f61eb416SIlia Diachkov static bool generateSpecConstantInst(const SPIRV::IncomingCall *Call, 2055f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 2056f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 2057f61eb416SIlia Diachkov // Lookup the instruction opcode in the TableGen records. 2058f61eb416SIlia Diachkov const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 2059f61eb416SIlia Diachkov unsigned Opcode = 2060f61eb416SIlia Diachkov SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode; 2061f61eb416SIlia Diachkov const MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 2062f61eb416SIlia Diachkov 2063f61eb416SIlia Diachkov switch (Opcode) { 2064f61eb416SIlia Diachkov case SPIRV::OpSpecConstant: { 2065f61eb416SIlia Diachkov // Build the SpecID decoration. 2066f61eb416SIlia Diachkov unsigned SpecId = 2067f61eb416SIlia Diachkov static_cast<unsigned>(getIConstVal(Call->Arguments[0], MRI)); 2068f61eb416SIlia Diachkov buildOpDecorate(Call->ReturnRegister, MIRBuilder, SPIRV::Decoration::SpecId, 2069f61eb416SIlia Diachkov {SpecId}); 2070f61eb416SIlia Diachkov // Determine the constant MI. 2071f61eb416SIlia Diachkov Register ConstRegister = Call->Arguments[1]; 2072f61eb416SIlia Diachkov const MachineInstr *Const = getDefInstrMaybeConstant(ConstRegister, MRI); 2073f61eb416SIlia Diachkov assert(Const && 2074f61eb416SIlia Diachkov (Const->getOpcode() == TargetOpcode::G_CONSTANT || 2075f61eb416SIlia Diachkov Const->getOpcode() == TargetOpcode::G_FCONSTANT) && 2076f61eb416SIlia Diachkov "Argument should be either an int or floating-point constant"); 2077f61eb416SIlia Diachkov // Determine the opcode and built the OpSpec MI. 2078f61eb416SIlia Diachkov const MachineOperand &ConstOperand = Const->getOperand(1); 2079f61eb416SIlia Diachkov if (Call->ReturnType->getOpcode() == SPIRV::OpTypeBool) { 2080f61eb416SIlia Diachkov assert(ConstOperand.isCImm() && "Int constant operand is expected"); 2081f61eb416SIlia Diachkov Opcode = ConstOperand.getCImm()->getValue().getZExtValue() 2082f61eb416SIlia Diachkov ? SPIRV::OpSpecConstantTrue 2083f61eb416SIlia Diachkov : SPIRV::OpSpecConstantFalse; 2084f61eb416SIlia Diachkov } 2085f61eb416SIlia Diachkov auto MIB = MIRBuilder.buildInstr(Opcode) 2086f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 2087f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(Call->ReturnType)); 2088f61eb416SIlia Diachkov 2089f61eb416SIlia Diachkov if (Call->ReturnType->getOpcode() != SPIRV::OpTypeBool) { 2090f61eb416SIlia Diachkov if (Const->getOpcode() == TargetOpcode::G_CONSTANT) 2091f61eb416SIlia Diachkov addNumImm(ConstOperand.getCImm()->getValue(), MIB); 2092f61eb416SIlia Diachkov else 2093f61eb416SIlia Diachkov addNumImm(ConstOperand.getFPImm()->getValueAPF().bitcastToAPInt(), MIB); 2094f61eb416SIlia Diachkov } 2095f61eb416SIlia Diachkov return true; 2096f61eb416SIlia Diachkov } 2097f61eb416SIlia Diachkov case SPIRV::OpSpecConstantComposite: { 2098f61eb416SIlia Diachkov auto MIB = MIRBuilder.buildInstr(Opcode) 2099f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 2100f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(Call->ReturnType)); 2101f61eb416SIlia Diachkov for (unsigned i = 0; i < Call->Arguments.size(); i++) 2102f61eb416SIlia Diachkov MIB.addUse(Call->Arguments[i]); 2103f61eb416SIlia Diachkov return true; 2104f61eb416SIlia Diachkov } 2105f61eb416SIlia Diachkov default: 2106f61eb416SIlia Diachkov return false; 2107f61eb416SIlia Diachkov } 2108f61eb416SIlia Diachkov } 2109f61eb416SIlia Diachkov 211074c66710SIlia Diachkov static bool buildNDRange(const SPIRV::IncomingCall *Call, 211174c66710SIlia Diachkov MachineIRBuilder &MIRBuilder, 211274c66710SIlia Diachkov SPIRVGlobalRegistry *GR) { 211374c66710SIlia Diachkov MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 211474c66710SIlia Diachkov SPIRVType *PtrType = GR->getSPIRVTypeForVReg(Call->Arguments[0]); 211574c66710SIlia Diachkov assert(PtrType->getOpcode() == SPIRV::OpTypePointer && 211674c66710SIlia Diachkov PtrType->getOperand(2).isReg()); 211774c66710SIlia Diachkov Register TypeReg = PtrType->getOperand(2).getReg(); 211874c66710SIlia Diachkov SPIRVType *StructType = GR->getSPIRVTypeForVReg(TypeReg); 211974c66710SIlia Diachkov MachineFunction &MF = MIRBuilder.getMF(); 2120f9c98068SVyacheslav Levytskyy Register TmpReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass); 212174c66710SIlia Diachkov GR->assignSPIRVTypeToVReg(StructType, TmpReg, MF); 212274c66710SIlia Diachkov // Skip the first arg, it's the destination pointer. OpBuildNDRange takes 212374c66710SIlia Diachkov // three other arguments, so pass zero constant on absence. 212474c66710SIlia Diachkov unsigned NumArgs = Call->Arguments.size(); 212574c66710SIlia Diachkov assert(NumArgs >= 2); 212674c66710SIlia Diachkov Register GlobalWorkSize = Call->Arguments[NumArgs < 4 ? 1 : 2]; 212774c66710SIlia Diachkov Register LocalWorkSize = 212874c66710SIlia Diachkov NumArgs == 2 ? Register(0) : Call->Arguments[NumArgs < 4 ? 2 : 3]; 212974c66710SIlia Diachkov Register GlobalWorkOffset = NumArgs <= 3 ? Register(0) : Call->Arguments[1]; 213074c66710SIlia Diachkov if (NumArgs < 4) { 213174c66710SIlia Diachkov Register Const; 213274c66710SIlia Diachkov SPIRVType *SpvTy = GR->getSPIRVTypeForVReg(GlobalWorkSize); 213374c66710SIlia Diachkov if (SpvTy->getOpcode() == SPIRV::OpTypePointer) { 213474c66710SIlia Diachkov MachineInstr *DefInstr = MRI->getUniqueVRegDef(GlobalWorkSize); 213574c66710SIlia Diachkov assert(DefInstr && isSpvIntrinsic(*DefInstr, Intrinsic::spv_gep) && 213674c66710SIlia Diachkov DefInstr->getOperand(3).isReg()); 213774c66710SIlia Diachkov Register GWSPtr = DefInstr->getOperand(3).getReg(); 213874c66710SIlia Diachkov // TODO: Maybe simplify generation of the type of the fields. 2139c18bcd0aSKazu Hirata unsigned Size = Call->Builtin->Name == "ndrange_3D" ? 3 : 2; 214074c66710SIlia Diachkov unsigned BitWidth = GR->getPointerSize() == 64 ? 64 : 32; 214174c66710SIlia Diachkov Type *BaseTy = IntegerType::get(MF.getFunction().getContext(), BitWidth); 214274c66710SIlia Diachkov Type *FieldTy = ArrayType::get(BaseTy, Size); 214374c66710SIlia Diachkov SPIRVType *SpvFieldTy = GR->getOrCreateSPIRVType(FieldTy, MIRBuilder); 2144f9c98068SVyacheslav Levytskyy GlobalWorkSize = MRI->createVirtualRegister(&SPIRV::iIDRegClass); 214574c66710SIlia Diachkov GR->assignSPIRVTypeToVReg(SpvFieldTy, GlobalWorkSize, MF); 214674c66710SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpLoad) 214774c66710SIlia Diachkov .addDef(GlobalWorkSize) 214874c66710SIlia Diachkov .addUse(GR->getSPIRVTypeID(SpvFieldTy)) 214974c66710SIlia Diachkov .addUse(GWSPtr); 2150f6aa5087SVyacheslav Levytskyy const SPIRVSubtarget &ST = 2151f6aa5087SVyacheslav Levytskyy cast<SPIRVSubtarget>(MIRBuilder.getMF().getSubtarget()); 2152f6aa5087SVyacheslav Levytskyy Const = GR->getOrCreateConstIntArray(0, Size, *MIRBuilder.getInsertPt(), 2153f6aa5087SVyacheslav Levytskyy SpvFieldTy, *ST.getInstrInfo()); 215474c66710SIlia Diachkov } else { 215574c66710SIlia Diachkov Const = GR->buildConstantInt(0, MIRBuilder, SpvTy); 215674c66710SIlia Diachkov } 215774c66710SIlia Diachkov if (!LocalWorkSize.isValid()) 215874c66710SIlia Diachkov LocalWorkSize = Const; 215974c66710SIlia Diachkov if (!GlobalWorkOffset.isValid()) 216074c66710SIlia Diachkov GlobalWorkOffset = Const; 216174c66710SIlia Diachkov } 216274c66710SIlia Diachkov assert(LocalWorkSize.isValid() && GlobalWorkOffset.isValid()); 216374c66710SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpBuildNDRange) 216474c66710SIlia Diachkov .addDef(TmpReg) 216574c66710SIlia Diachkov .addUse(TypeReg) 216674c66710SIlia Diachkov .addUse(GlobalWorkSize) 216774c66710SIlia Diachkov .addUse(LocalWorkSize) 216874c66710SIlia Diachkov .addUse(GlobalWorkOffset); 216974c66710SIlia Diachkov return MIRBuilder.buildInstr(SPIRV::OpStore) 217074c66710SIlia Diachkov .addUse(Call->Arguments[0]) 217174c66710SIlia Diachkov .addUse(TmpReg); 217274c66710SIlia Diachkov } 217374c66710SIlia Diachkov 2174748922b3SIlia Diachkov // TODO: maybe move to the global register. 2175748922b3SIlia Diachkov static SPIRVType * 2176748922b3SIlia Diachkov getOrCreateSPIRVDeviceEventPointer(MachineIRBuilder &MIRBuilder, 2177748922b3SIlia Diachkov SPIRVGlobalRegistry *GR) { 2178748922b3SIlia Diachkov LLVMContext &Context = MIRBuilder.getMF().getFunction().getContext(); 2179748922b3SIlia Diachkov unsigned SC1 = storageClassToAddressSpace(SPIRV::StorageClass::Generic); 2180*d459784cSMats Jun Larsen Type *PtrType = PointerType::get(Context, SC1); 2181748922b3SIlia Diachkov return GR->getOrCreateSPIRVType(PtrType, MIRBuilder); 2182748922b3SIlia Diachkov } 2183748922b3SIlia Diachkov 2184748922b3SIlia Diachkov static bool buildEnqueueKernel(const SPIRV::IncomingCall *Call, 2185748922b3SIlia Diachkov MachineIRBuilder &MIRBuilder, 2186748922b3SIlia Diachkov SPIRVGlobalRegistry *GR) { 2187748922b3SIlia Diachkov MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 2188748922b3SIlia Diachkov const DataLayout &DL = MIRBuilder.getDataLayout(); 2189c2483ed5SVyacheslav Levytskyy bool IsSpirvOp = Call->isSpirvOp(); 2190c2483ed5SVyacheslav Levytskyy bool HasEvents = Call->Builtin->Name.contains("events") || IsSpirvOp; 2191748922b3SIlia Diachkov const SPIRVType *Int32Ty = GR->getOrCreateSPIRVIntegerType(32, MIRBuilder); 2192748922b3SIlia Diachkov 2193748922b3SIlia Diachkov // Make vararg instructions before OpEnqueueKernel. 2194748922b3SIlia Diachkov // Local sizes arguments: Sizes of block invoke arguments. Clang generates 2195748922b3SIlia Diachkov // local size operands as an array, so we need to unpack them. 2196748922b3SIlia Diachkov SmallVector<Register, 16> LocalSizes; 219789d09373SKazu Hirata if (Call->Builtin->Name.contains("_varargs") || IsSpirvOp) { 2198748922b3SIlia Diachkov const unsigned LocalSizeArrayIdx = HasEvents ? 9 : 6; 2199748922b3SIlia Diachkov Register GepReg = Call->Arguments[LocalSizeArrayIdx]; 2200748922b3SIlia Diachkov MachineInstr *GepMI = MRI->getUniqueVRegDef(GepReg); 2201748922b3SIlia Diachkov assert(isSpvIntrinsic(*GepMI, Intrinsic::spv_gep) && 2202748922b3SIlia Diachkov GepMI->getOperand(3).isReg()); 2203748922b3SIlia Diachkov Register ArrayReg = GepMI->getOperand(3).getReg(); 2204748922b3SIlia Diachkov MachineInstr *ArrayMI = MRI->getUniqueVRegDef(ArrayReg); 2205748922b3SIlia Diachkov const Type *LocalSizeTy = getMachineInstrType(ArrayMI); 2206748922b3SIlia Diachkov assert(LocalSizeTy && "Local size type is expected"); 2207748922b3SIlia Diachkov const uint64_t LocalSizeNum = 2208748922b3SIlia Diachkov cast<ArrayType>(LocalSizeTy)->getNumElements(); 2209748922b3SIlia Diachkov unsigned SC = storageClassToAddressSpace(SPIRV::StorageClass::Generic); 2210748922b3SIlia Diachkov const LLT LLType = LLT::pointer(SC, GR->getPointerSize()); 2211748922b3SIlia Diachkov const SPIRVType *PointerSizeTy = GR->getOrCreateSPIRVPointerType( 2212748922b3SIlia Diachkov Int32Ty, MIRBuilder, SPIRV::StorageClass::Function); 2213748922b3SIlia Diachkov for (unsigned I = 0; I < LocalSizeNum; ++I) { 2214b5132b7dSVyacheslav Levytskyy Register Reg = MRI->createVirtualRegister(&SPIRV::pIDRegClass); 221574c66710SIlia Diachkov MRI->setType(Reg, LLType); 2216748922b3SIlia Diachkov GR->assignSPIRVTypeToVReg(PointerSizeTy, Reg, MIRBuilder.getMF()); 2217d9847cdeSSameer Sahasrabuddhe auto GEPInst = MIRBuilder.buildIntrinsic( 2218d9847cdeSSameer Sahasrabuddhe Intrinsic::spv_gep, ArrayRef<Register>{Reg}, true, false); 2219748922b3SIlia Diachkov GEPInst 2220748922b3SIlia Diachkov .addImm(GepMI->getOperand(2).getImm()) // In bound. 2221748922b3SIlia Diachkov .addUse(ArrayMI->getOperand(0).getReg()) // Alloca. 222267d3ef74SVyacheslav Levytskyy .addUse(buildConstantIntReg32(0, MIRBuilder, GR)) // Indices. 222367d3ef74SVyacheslav Levytskyy .addUse(buildConstantIntReg32(I, MIRBuilder, GR)); 2224748922b3SIlia Diachkov LocalSizes.push_back(Reg); 2225748922b3SIlia Diachkov } 2226748922b3SIlia Diachkov } 2227748922b3SIlia Diachkov 2228748922b3SIlia Diachkov // SPIRV OpEnqueueKernel instruction has 10+ arguments. 2229748922b3SIlia Diachkov auto MIB = MIRBuilder.buildInstr(SPIRV::OpEnqueueKernel) 2230748922b3SIlia Diachkov .addDef(Call->ReturnRegister) 2231748922b3SIlia Diachkov .addUse(GR->getSPIRVTypeID(Int32Ty)); 2232748922b3SIlia Diachkov 2233748922b3SIlia Diachkov // Copy all arguments before block invoke function pointer. 2234748922b3SIlia Diachkov const unsigned BlockFIdx = HasEvents ? 6 : 3; 2235748922b3SIlia Diachkov for (unsigned i = 0; i < BlockFIdx; i++) 2236748922b3SIlia Diachkov MIB.addUse(Call->Arguments[i]); 2237748922b3SIlia Diachkov 2238748922b3SIlia Diachkov // If there are no event arguments in the original call, add dummy ones. 2239748922b3SIlia Diachkov if (!HasEvents) { 224067d3ef74SVyacheslav Levytskyy MIB.addUse(buildConstantIntReg32(0, MIRBuilder, GR)); // Dummy num events. 2241748922b3SIlia Diachkov Register NullPtr = GR->getOrCreateConstNullPtr( 2242748922b3SIlia Diachkov MIRBuilder, getOrCreateSPIRVDeviceEventPointer(MIRBuilder, GR)); 2243748922b3SIlia Diachkov MIB.addUse(NullPtr); // Dummy wait events. 2244748922b3SIlia Diachkov MIB.addUse(NullPtr); // Dummy ret event. 2245748922b3SIlia Diachkov } 2246748922b3SIlia Diachkov 2247748922b3SIlia Diachkov MachineInstr *BlockMI = getBlockStructInstr(Call->Arguments[BlockFIdx], MRI); 2248748922b3SIlia Diachkov assert(BlockMI->getOpcode() == TargetOpcode::G_GLOBAL_VALUE); 2249748922b3SIlia Diachkov // Invoke: Pointer to invoke function. 2250748922b3SIlia Diachkov MIB.addGlobalAddress(BlockMI->getOperand(1).getGlobal()); 2251748922b3SIlia Diachkov 2252748922b3SIlia Diachkov Register BlockLiteralReg = Call->Arguments[BlockFIdx + 1]; 2253748922b3SIlia Diachkov // Param: Pointer to block literal. 2254748922b3SIlia Diachkov MIB.addUse(BlockLiteralReg); 2255748922b3SIlia Diachkov 2256748922b3SIlia Diachkov Type *PType = const_cast<Type *>(getBlockStructType(BlockLiteralReg, MRI)); 2257748922b3SIlia Diachkov // TODO: these numbers should be obtained from block literal structure. 2258748922b3SIlia Diachkov // Param Size: Size of block literal structure. 225967d3ef74SVyacheslav Levytskyy MIB.addUse(buildConstantIntReg32(DL.getTypeStoreSize(PType), MIRBuilder, GR)); 2260748922b3SIlia Diachkov // Param Aligment: Aligment of block literal structure. 226167d3ef74SVyacheslav Levytskyy MIB.addUse(buildConstantIntReg32(DL.getPrefTypeAlign(PType).value(), 226267d3ef74SVyacheslav Levytskyy MIRBuilder, GR)); 2263748922b3SIlia Diachkov 2264748922b3SIlia Diachkov for (unsigned i = 0; i < LocalSizes.size(); i++) 2265748922b3SIlia Diachkov MIB.addUse(LocalSizes[i]); 2266748922b3SIlia Diachkov return true; 2267748922b3SIlia Diachkov } 2268748922b3SIlia Diachkov 2269f61eb416SIlia Diachkov static bool generateEnqueueInst(const SPIRV::IncomingCall *Call, 2270f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 2271f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 2272f61eb416SIlia Diachkov // Lookup the instruction opcode in the TableGen records. 2273f61eb416SIlia Diachkov const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 2274f61eb416SIlia Diachkov unsigned Opcode = 2275f61eb416SIlia Diachkov SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode; 2276f61eb416SIlia Diachkov 2277f61eb416SIlia Diachkov switch (Opcode) { 2278f61eb416SIlia Diachkov case SPIRV::OpRetainEvent: 2279f61eb416SIlia Diachkov case SPIRV::OpReleaseEvent: 2280f61eb416SIlia Diachkov return MIRBuilder.buildInstr(Opcode).addUse(Call->Arguments[0]); 2281f61eb416SIlia Diachkov case SPIRV::OpCreateUserEvent: 2282f61eb416SIlia Diachkov case SPIRV::OpGetDefaultQueue: 2283f61eb416SIlia Diachkov return MIRBuilder.buildInstr(Opcode) 2284f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 2285f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(Call->ReturnType)); 2286f61eb416SIlia Diachkov case SPIRV::OpIsValidEvent: 2287f61eb416SIlia Diachkov return MIRBuilder.buildInstr(Opcode) 2288f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 2289f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(Call->ReturnType)) 2290f61eb416SIlia Diachkov .addUse(Call->Arguments[0]); 2291f61eb416SIlia Diachkov case SPIRV::OpSetUserEventStatus: 2292f61eb416SIlia Diachkov return MIRBuilder.buildInstr(Opcode) 2293f61eb416SIlia Diachkov .addUse(Call->Arguments[0]) 2294f61eb416SIlia Diachkov .addUse(Call->Arguments[1]); 2295f61eb416SIlia Diachkov case SPIRV::OpCaptureEventProfilingInfo: 2296f61eb416SIlia Diachkov return MIRBuilder.buildInstr(Opcode) 2297f61eb416SIlia Diachkov .addUse(Call->Arguments[0]) 2298f61eb416SIlia Diachkov .addUse(Call->Arguments[1]) 2299f61eb416SIlia Diachkov .addUse(Call->Arguments[2]); 230074c66710SIlia Diachkov case SPIRV::OpBuildNDRange: 230174c66710SIlia Diachkov return buildNDRange(Call, MIRBuilder, GR); 2302748922b3SIlia Diachkov case SPIRV::OpEnqueueKernel: 2303748922b3SIlia Diachkov return buildEnqueueKernel(Call, MIRBuilder, GR); 2304f61eb416SIlia Diachkov default: 2305f61eb416SIlia Diachkov return false; 2306f61eb416SIlia Diachkov } 2307f61eb416SIlia Diachkov } 2308f61eb416SIlia Diachkov 2309f61eb416SIlia Diachkov static bool generateAsyncCopy(const SPIRV::IncomingCall *Call, 2310f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 2311f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 2312f61eb416SIlia Diachkov // Lookup the instruction opcode in the TableGen records. 2313f61eb416SIlia Diachkov const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 2314f61eb416SIlia Diachkov unsigned Opcode = 2315f61eb416SIlia Diachkov SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode; 23161ed1ec9aSVyacheslav Levytskyy 23171ed1ec9aSVyacheslav Levytskyy bool IsSet = Opcode == SPIRV::OpGroupAsyncCopy; 23181ed1ec9aSVyacheslav Levytskyy Register TypeReg = GR->getSPIRVTypeID(Call->ReturnType); 23191ed1ec9aSVyacheslav Levytskyy if (Call->isSpirvOp()) 23201ed1ec9aSVyacheslav Levytskyy return buildOpFromWrapper(MIRBuilder, Opcode, Call, 23211ed1ec9aSVyacheslav Levytskyy IsSet ? TypeReg : Register(0)); 23221ed1ec9aSVyacheslav Levytskyy 232367d3ef74SVyacheslav Levytskyy auto Scope = buildConstantIntReg32(SPIRV::Scope::Workgroup, MIRBuilder, GR); 2324f61eb416SIlia Diachkov 2325f61eb416SIlia Diachkov switch (Opcode) { 2326505cd125SVyacheslav Levytskyy case SPIRV::OpGroupAsyncCopy: { 2327505cd125SVyacheslav Levytskyy SPIRVType *NewType = 2328505cd125SVyacheslav Levytskyy Call->ReturnType->getOpcode() == SPIRV::OpTypeEvent 2329505cd125SVyacheslav Levytskyy ? nullptr 2330505cd125SVyacheslav Levytskyy : GR->getOrCreateSPIRVTypeByName("spirv.Event", MIRBuilder); 2331505cd125SVyacheslav Levytskyy Register TypeReg = GR->getSPIRVTypeID(NewType ? NewType : Call->ReturnType); 2332505cd125SVyacheslav Levytskyy unsigned NumArgs = Call->Arguments.size(); 2333505cd125SVyacheslav Levytskyy Register EventReg = Call->Arguments[NumArgs - 1]; 2334505cd125SVyacheslav Levytskyy bool Res = MIRBuilder.buildInstr(Opcode) 2335f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 2336505cd125SVyacheslav Levytskyy .addUse(TypeReg) 2337f61eb416SIlia Diachkov .addUse(Scope) 2338f61eb416SIlia Diachkov .addUse(Call->Arguments[0]) 2339f61eb416SIlia Diachkov .addUse(Call->Arguments[1]) 2340f61eb416SIlia Diachkov .addUse(Call->Arguments[2]) 2341505cd125SVyacheslav Levytskyy .addUse(Call->Arguments.size() > 4 2342505cd125SVyacheslav Levytskyy ? Call->Arguments[3] 234367d3ef74SVyacheslav Levytskyy : buildConstantIntReg32(1, MIRBuilder, GR)) 2344505cd125SVyacheslav Levytskyy .addUse(EventReg); 2345505cd125SVyacheslav Levytskyy if (NewType != nullptr) 2346505cd125SVyacheslav Levytskyy insertAssignInstr(Call->ReturnRegister, nullptr, NewType, GR, MIRBuilder, 2347505cd125SVyacheslav Levytskyy MIRBuilder.getMF().getRegInfo()); 2348505cd125SVyacheslav Levytskyy return Res; 2349505cd125SVyacheslav Levytskyy } 2350f61eb416SIlia Diachkov case SPIRV::OpGroupWaitEvents: 2351f61eb416SIlia Diachkov return MIRBuilder.buildInstr(Opcode) 2352f61eb416SIlia Diachkov .addUse(Scope) 2353f61eb416SIlia Diachkov .addUse(Call->Arguments[0]) 2354f61eb416SIlia Diachkov .addUse(Call->Arguments[1]); 2355f61eb416SIlia Diachkov default: 2356f61eb416SIlia Diachkov return false; 2357f61eb416SIlia Diachkov } 2358f61eb416SIlia Diachkov } 2359f61eb416SIlia Diachkov 2360f61eb416SIlia Diachkov static bool generateConvertInst(const StringRef DemangledCall, 2361f61eb416SIlia Diachkov const SPIRV::IncomingCall *Call, 2362f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 2363f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 2364f61eb416SIlia Diachkov // Lookup the conversion builtin in the TableGen records. 2365f61eb416SIlia Diachkov const SPIRV::ConvertBuiltin *Builtin = 2366f61eb416SIlia Diachkov SPIRV::lookupConvertBuiltin(Call->Builtin->Name, Call->Builtin->Set); 2367f61eb416SIlia Diachkov 236824cee1c4SVyacheslav Levytskyy if (!Builtin && Call->isSpirvOp()) { 236924cee1c4SVyacheslav Levytskyy const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 237024cee1c4SVyacheslav Levytskyy unsigned Opcode = 237124cee1c4SVyacheslav Levytskyy SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode; 237224cee1c4SVyacheslav Levytskyy return buildOpFromWrapper(MIRBuilder, Opcode, Call, 237324cee1c4SVyacheslav Levytskyy GR->getSPIRVTypeID(Call->ReturnType)); 237424cee1c4SVyacheslav Levytskyy } 237524cee1c4SVyacheslav Levytskyy 2376f61eb416SIlia Diachkov if (Builtin->IsSaturated) 2377f61eb416SIlia Diachkov buildOpDecorate(Call->ReturnRegister, MIRBuilder, 2378f61eb416SIlia Diachkov SPIRV::Decoration::SaturatedConversion, {}); 2379f61eb416SIlia Diachkov if (Builtin->IsRounded) 2380f61eb416SIlia Diachkov buildOpDecorate(Call->ReturnRegister, MIRBuilder, 2381d7259bb7SIlia Diachkov SPIRV::Decoration::FPRoundingMode, 2382d7259bb7SIlia Diachkov {(unsigned)Builtin->RoundingMode}); 2383f61eb416SIlia Diachkov 23848f30b623SVyacheslav Levytskyy std::string NeedExtMsg; // no errors if empty 23858f30b623SVyacheslav Levytskyy bool IsRightComponentsNumber = true; // check if input/output accepts vectors 2386f61eb416SIlia Diachkov unsigned Opcode = SPIRV::OpNop; 2387f61eb416SIlia Diachkov if (GR->isScalarOrVectorOfType(Call->Arguments[0], SPIRV::OpTypeInt)) { 2388f61eb416SIlia Diachkov // Int -> ... 2389f61eb416SIlia Diachkov if (GR->isScalarOrVectorOfType(Call->ReturnRegister, SPIRV::OpTypeInt)) { 2390f61eb416SIlia Diachkov // Int -> Int 2391f61eb416SIlia Diachkov if (Builtin->IsSaturated) 2392f61eb416SIlia Diachkov Opcode = Builtin->IsDestinationSigned ? SPIRV::OpSatConvertUToS 2393f61eb416SIlia Diachkov : SPIRV::OpSatConvertSToU; 2394f61eb416SIlia Diachkov else 2395f61eb416SIlia Diachkov Opcode = Builtin->IsDestinationSigned ? SPIRV::OpUConvert 2396f61eb416SIlia Diachkov : SPIRV::OpSConvert; 2397f61eb416SIlia Diachkov } else if (GR->isScalarOrVectorOfType(Call->ReturnRegister, 2398f61eb416SIlia Diachkov SPIRV::OpTypeFloat)) { 2399f61eb416SIlia Diachkov // Int -> Float 24008f30b623SVyacheslav Levytskyy if (Builtin->IsBfloat16) { 24018f30b623SVyacheslav Levytskyy const auto *ST = static_cast<const SPIRVSubtarget *>( 24028f30b623SVyacheslav Levytskyy &MIRBuilder.getMF().getSubtarget()); 24038f30b623SVyacheslav Levytskyy if (!ST->canUseExtension( 24048f30b623SVyacheslav Levytskyy SPIRV::Extension::SPV_INTEL_bfloat16_conversion)) 24058f30b623SVyacheslav Levytskyy NeedExtMsg = "SPV_INTEL_bfloat16_conversion"; 24068f30b623SVyacheslav Levytskyy IsRightComponentsNumber = 24078f30b623SVyacheslav Levytskyy GR->getScalarOrVectorComponentCount(Call->Arguments[0]) == 24088f30b623SVyacheslav Levytskyy GR->getScalarOrVectorComponentCount(Call->ReturnRegister); 24098f30b623SVyacheslav Levytskyy Opcode = SPIRV::OpConvertBF16ToFINTEL; 24108f30b623SVyacheslav Levytskyy } else { 2411f61eb416SIlia Diachkov bool IsSourceSigned = 2412f61eb416SIlia Diachkov DemangledCall[DemangledCall.find_first_of('(') + 1] != 'u'; 2413f61eb416SIlia Diachkov Opcode = IsSourceSigned ? SPIRV::OpConvertSToF : SPIRV::OpConvertUToF; 2414f61eb416SIlia Diachkov } 24158f30b623SVyacheslav Levytskyy } 2416f61eb416SIlia Diachkov } else if (GR->isScalarOrVectorOfType(Call->Arguments[0], 2417f61eb416SIlia Diachkov SPIRV::OpTypeFloat)) { 2418f61eb416SIlia Diachkov // Float -> ... 24198f30b623SVyacheslav Levytskyy if (GR->isScalarOrVectorOfType(Call->ReturnRegister, SPIRV::OpTypeInt)) { 2420f61eb416SIlia Diachkov // Float -> Int 24218f30b623SVyacheslav Levytskyy if (Builtin->IsBfloat16) { 24228f30b623SVyacheslav Levytskyy const auto *ST = static_cast<const SPIRVSubtarget *>( 24238f30b623SVyacheslav Levytskyy &MIRBuilder.getMF().getSubtarget()); 24248f30b623SVyacheslav Levytskyy if (!ST->canUseExtension( 24258f30b623SVyacheslav Levytskyy SPIRV::Extension::SPV_INTEL_bfloat16_conversion)) 24268f30b623SVyacheslav Levytskyy NeedExtMsg = "SPV_INTEL_bfloat16_conversion"; 24278f30b623SVyacheslav Levytskyy IsRightComponentsNumber = 24288f30b623SVyacheslav Levytskyy GR->getScalarOrVectorComponentCount(Call->Arguments[0]) == 24298f30b623SVyacheslav Levytskyy GR->getScalarOrVectorComponentCount(Call->ReturnRegister); 24308f30b623SVyacheslav Levytskyy Opcode = SPIRV::OpConvertFToBF16INTEL; 24318f30b623SVyacheslav Levytskyy } else { 2432f61eb416SIlia Diachkov Opcode = Builtin->IsDestinationSigned ? SPIRV::OpConvertFToS 2433f61eb416SIlia Diachkov : SPIRV::OpConvertFToU; 24348f30b623SVyacheslav Levytskyy } 24358f30b623SVyacheslav Levytskyy } else if (GR->isScalarOrVectorOfType(Call->ReturnRegister, 24368f30b623SVyacheslav Levytskyy SPIRV::OpTypeFloat)) { 2437f61eb416SIlia Diachkov // Float -> Float 2438f61eb416SIlia Diachkov Opcode = SPIRV::OpFConvert; 2439f61eb416SIlia Diachkov } 24408f30b623SVyacheslav Levytskyy } 2441f61eb416SIlia Diachkov 24428f30b623SVyacheslav Levytskyy if (!NeedExtMsg.empty()) { 24438f30b623SVyacheslav Levytskyy std::string DiagMsg = std::string(Builtin->Name) + 24448f30b623SVyacheslav Levytskyy ": the builtin requires the following SPIR-V " 24458f30b623SVyacheslav Levytskyy "extension: " + 24468f30b623SVyacheslav Levytskyy NeedExtMsg; 24478f30b623SVyacheslav Levytskyy report_fatal_error(DiagMsg.c_str(), false); 24488f30b623SVyacheslav Levytskyy } 24498f30b623SVyacheslav Levytskyy if (!IsRightComponentsNumber) { 24508f30b623SVyacheslav Levytskyy std::string DiagMsg = 24518f30b623SVyacheslav Levytskyy std::string(Builtin->Name) + 24528f30b623SVyacheslav Levytskyy ": result and argument must have the same number of components"; 24538f30b623SVyacheslav Levytskyy report_fatal_error(DiagMsg.c_str(), false); 24548f30b623SVyacheslav Levytskyy } 2455f61eb416SIlia Diachkov assert(Opcode != SPIRV::OpNop && 2456f61eb416SIlia Diachkov "Conversion between the types not implemented!"); 2457f61eb416SIlia Diachkov 2458f61eb416SIlia Diachkov MIRBuilder.buildInstr(Opcode) 2459f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 2460f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(Call->ReturnType)) 2461f61eb416SIlia Diachkov .addUse(Call->Arguments[0]); 2462f61eb416SIlia Diachkov return true; 2463f61eb416SIlia Diachkov } 2464f61eb416SIlia Diachkov 2465f61eb416SIlia Diachkov static bool generateVectorLoadStoreInst(const SPIRV::IncomingCall *Call, 2466f61eb416SIlia Diachkov MachineIRBuilder &MIRBuilder, 2467f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 2468f61eb416SIlia Diachkov // Lookup the vector load/store builtin in the TableGen records. 2469f61eb416SIlia Diachkov const SPIRV::VectorLoadStoreBuiltin *Builtin = 2470f61eb416SIlia Diachkov SPIRV::lookupVectorLoadStoreBuiltin(Call->Builtin->Name, 2471f61eb416SIlia Diachkov Call->Builtin->Set); 2472f61eb416SIlia Diachkov // Build extended instruction. 2473f61eb416SIlia Diachkov auto MIB = 2474f61eb416SIlia Diachkov MIRBuilder.buildInstr(SPIRV::OpExtInst) 2475f61eb416SIlia Diachkov .addDef(Call->ReturnRegister) 2476f61eb416SIlia Diachkov .addUse(GR->getSPIRVTypeID(Call->ReturnType)) 2477f61eb416SIlia Diachkov .addImm(static_cast<uint32_t>(SPIRV::InstructionSet::OpenCL_std)) 2478f61eb416SIlia Diachkov .addImm(Builtin->Number); 2479f61eb416SIlia Diachkov for (auto Argument : Call->Arguments) 2480f61eb416SIlia Diachkov MIB.addUse(Argument); 248143222bd3SMichal Paszkowski if (Builtin->Name.contains("load") && Builtin->ElementCount > 1) 248203203b79SMichal Paszkowski MIB.addImm(Builtin->ElementCount); 2483f61eb416SIlia Diachkov 2484f61eb416SIlia Diachkov // Rounding mode should be passed as a last argument in the MI for builtins 2485f61eb416SIlia Diachkov // like "vstorea_halfn_r". 2486f61eb416SIlia Diachkov if (Builtin->IsRounded) 2487f61eb416SIlia Diachkov MIB.addImm(static_cast<uint32_t>(Builtin->RoundingMode)); 2488f61eb416SIlia Diachkov return true; 2489f61eb416SIlia Diachkov } 2490f61eb416SIlia Diachkov 24910b0224bcSIlia Diachkov static bool generateLoadStoreInst(const SPIRV::IncomingCall *Call, 24920b0224bcSIlia Diachkov MachineIRBuilder &MIRBuilder, 24930b0224bcSIlia Diachkov SPIRVGlobalRegistry *GR) { 24940b0224bcSIlia Diachkov // Lookup the instruction opcode in the TableGen records. 24950b0224bcSIlia Diachkov const SPIRV::DemangledBuiltin *Builtin = Call->Builtin; 24960b0224bcSIlia Diachkov unsigned Opcode = 24970b0224bcSIlia Diachkov SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode; 24980b0224bcSIlia Diachkov bool IsLoad = Opcode == SPIRV::OpLoad; 24990b0224bcSIlia Diachkov // Build the instruction. 25000b0224bcSIlia Diachkov auto MIB = MIRBuilder.buildInstr(Opcode); 25010b0224bcSIlia Diachkov if (IsLoad) { 25020b0224bcSIlia Diachkov MIB.addDef(Call->ReturnRegister); 25030b0224bcSIlia Diachkov MIB.addUse(GR->getSPIRVTypeID(Call->ReturnType)); 25040b0224bcSIlia Diachkov } 25050b0224bcSIlia Diachkov // Add a pointer to the value to load/store. 25060b0224bcSIlia Diachkov MIB.addUse(Call->Arguments[0]); 25070b0224bcSIlia Diachkov MachineRegisterInfo *MRI = MIRBuilder.getMRI(); 250874c66710SIlia Diachkov // Add a value to store. 250967d3ef74SVyacheslav Levytskyy if (!IsLoad) 251074c66710SIlia Diachkov MIB.addUse(Call->Arguments[1]); 251174c66710SIlia Diachkov // Add optional memory attributes and an alignment. 25120b0224bcSIlia Diachkov unsigned NumArgs = Call->Arguments.size(); 251367d3ef74SVyacheslav Levytskyy if ((IsLoad && NumArgs >= 2) || NumArgs >= 3) 25140b0224bcSIlia Diachkov MIB.addImm(getConstFromIntrinsic(Call->Arguments[IsLoad ? 1 : 2], MRI)); 251567d3ef74SVyacheslav Levytskyy if ((IsLoad && NumArgs >= 3) || NumArgs >= 4) 25160b0224bcSIlia Diachkov MIB.addImm(getConstFromIntrinsic(Call->Arguments[IsLoad ? 2 : 3], MRI)); 25170b0224bcSIlia Diachkov return true; 25180b0224bcSIlia Diachkov } 25190b0224bcSIlia Diachkov 2520f61eb416SIlia Diachkov namespace SPIRV { 2521bf9e9e5eSVyacheslav Levytskyy // Try to find a builtin function attributes by a demangled function name and 2522bf9e9e5eSVyacheslav Levytskyy // return a tuple <builtin group, op code, ext instruction number>, or a special 2523bf9e9e5eSVyacheslav Levytskyy // tuple value <-1, 0, 0> if the builtin function is not found. 2524bf9e9e5eSVyacheslav Levytskyy // Not all builtin functions are supported, only those with a ready-to-use op 2525bf9e9e5eSVyacheslav Levytskyy // code or instruction number defined in TableGen. 2526bf9e9e5eSVyacheslav Levytskyy // TODO: consider a major rework of mapping demangled calls into a builtin 2527bf9e9e5eSVyacheslav Levytskyy // functions to unify search and decrease number of individual cases. 2528bf9e9e5eSVyacheslav Levytskyy std::tuple<int, unsigned, unsigned> 2529bf9e9e5eSVyacheslav Levytskyy mapBuiltinToOpcode(const StringRef DemangledCall, 2530bf9e9e5eSVyacheslav Levytskyy SPIRV::InstructionSet::InstructionSet Set) { 2531bf9e9e5eSVyacheslav Levytskyy Register Reg; 2532bf9e9e5eSVyacheslav Levytskyy SmallVector<Register> Args; 2533bf9e9e5eSVyacheslav Levytskyy std::unique_ptr<const IncomingCall> Call = 2534bf9e9e5eSVyacheslav Levytskyy lookupBuiltin(DemangledCall, Set, Reg, nullptr, Args); 2535bf9e9e5eSVyacheslav Levytskyy if (!Call) 2536bf9e9e5eSVyacheslav Levytskyy return std::make_tuple(-1, 0, 0); 2537bf9e9e5eSVyacheslav Levytskyy 2538bf9e9e5eSVyacheslav Levytskyy switch (Call->Builtin->Group) { 2539bf9e9e5eSVyacheslav Levytskyy case SPIRV::Relational: 2540bf9e9e5eSVyacheslav Levytskyy case SPIRV::Atomic: 2541bf9e9e5eSVyacheslav Levytskyy case SPIRV::Barrier: 2542bf9e9e5eSVyacheslav Levytskyy case SPIRV::CastToPtr: 2543bf9e9e5eSVyacheslav Levytskyy case SPIRV::ImageMiscQuery: 2544bf9e9e5eSVyacheslav Levytskyy case SPIRV::SpecConstant: 2545bf9e9e5eSVyacheslav Levytskyy case SPIRV::Enqueue: 2546bf9e9e5eSVyacheslav Levytskyy case SPIRV::AsyncCopy: 2547bf9e9e5eSVyacheslav Levytskyy case SPIRV::LoadStore: 2548bf9e9e5eSVyacheslav Levytskyy case SPIRV::CoopMatr: 2549bf9e9e5eSVyacheslav Levytskyy if (const auto *R = 2550bf9e9e5eSVyacheslav Levytskyy SPIRV::lookupNativeBuiltin(Call->Builtin->Name, Call->Builtin->Set)) 2551bf9e9e5eSVyacheslav Levytskyy return std::make_tuple(Call->Builtin->Group, R->Opcode, 0); 2552bf9e9e5eSVyacheslav Levytskyy break; 2553bf9e9e5eSVyacheslav Levytskyy case SPIRV::Extended: 2554bf9e9e5eSVyacheslav Levytskyy if (const auto *R = SPIRV::lookupExtendedBuiltin(Call->Builtin->Name, 2555bf9e9e5eSVyacheslav Levytskyy Call->Builtin->Set)) 2556bf9e9e5eSVyacheslav Levytskyy return std::make_tuple(Call->Builtin->Group, 0, R->Number); 2557bf9e9e5eSVyacheslav Levytskyy break; 2558bf9e9e5eSVyacheslav Levytskyy case SPIRV::VectorLoadStore: 2559bf9e9e5eSVyacheslav Levytskyy if (const auto *R = SPIRV::lookupVectorLoadStoreBuiltin(Call->Builtin->Name, 2560bf9e9e5eSVyacheslav Levytskyy Call->Builtin->Set)) 2561bf9e9e5eSVyacheslav Levytskyy return std::make_tuple(SPIRV::Extended, 0, R->Number); 2562bf9e9e5eSVyacheslav Levytskyy break; 2563bf9e9e5eSVyacheslav Levytskyy case SPIRV::Group: 2564bf9e9e5eSVyacheslav Levytskyy if (const auto *R = SPIRV::lookupGroupBuiltin(Call->Builtin->Name)) 2565bf9e9e5eSVyacheslav Levytskyy return std::make_tuple(Call->Builtin->Group, R->Opcode, 0); 2566bf9e9e5eSVyacheslav Levytskyy break; 2567bf9e9e5eSVyacheslav Levytskyy case SPIRV::AtomicFloating: 2568bf9e9e5eSVyacheslav Levytskyy if (const auto *R = SPIRV::lookupAtomicFloatingBuiltin(Call->Builtin->Name)) 2569bf9e9e5eSVyacheslav Levytskyy return std::make_tuple(Call->Builtin->Group, R->Opcode, 0); 2570bf9e9e5eSVyacheslav Levytskyy break; 2571bf9e9e5eSVyacheslav Levytskyy case SPIRV::IntelSubgroups: 2572bf9e9e5eSVyacheslav Levytskyy if (const auto *R = SPIRV::lookupIntelSubgroupsBuiltin(Call->Builtin->Name)) 2573bf9e9e5eSVyacheslav Levytskyy return std::make_tuple(Call->Builtin->Group, R->Opcode, 0); 2574bf9e9e5eSVyacheslav Levytskyy break; 2575bf9e9e5eSVyacheslav Levytskyy case SPIRV::GroupUniform: 2576bf9e9e5eSVyacheslav Levytskyy if (const auto *R = SPIRV::lookupGroupUniformBuiltin(Call->Builtin->Name)) 2577bf9e9e5eSVyacheslav Levytskyy return std::make_tuple(Call->Builtin->Group, R->Opcode, 0); 2578bf9e9e5eSVyacheslav Levytskyy break; 2579bf9e9e5eSVyacheslav Levytskyy case SPIRV::WriteImage: 2580bf9e9e5eSVyacheslav Levytskyy return std::make_tuple(Call->Builtin->Group, SPIRV::OpImageWrite, 0); 2581bf9e9e5eSVyacheslav Levytskyy case SPIRV::Select: 2582bf9e9e5eSVyacheslav Levytskyy return std::make_tuple(Call->Builtin->Group, TargetOpcode::G_SELECT, 0); 2583bf9e9e5eSVyacheslav Levytskyy case SPIRV::Construct: 2584bf9e9e5eSVyacheslav Levytskyy return std::make_tuple(Call->Builtin->Group, SPIRV::OpCompositeConstruct, 2585bf9e9e5eSVyacheslav Levytskyy 0); 2586bf9e9e5eSVyacheslav Levytskyy case SPIRV::KernelClock: 2587bf9e9e5eSVyacheslav Levytskyy return std::make_tuple(Call->Builtin->Group, SPIRV::OpReadClockKHR, 0); 2588bf9e9e5eSVyacheslav Levytskyy default: 2589bf9e9e5eSVyacheslav Levytskyy return std::make_tuple(-1, 0, 0); 2590bf9e9e5eSVyacheslav Levytskyy } 2591bf9e9e5eSVyacheslav Levytskyy return std::make_tuple(-1, 0, 0); 2592bf9e9e5eSVyacheslav Levytskyy } 2593bf9e9e5eSVyacheslav Levytskyy 2594b0df7040SFangrui Song std::optional<bool> lowerBuiltin(const StringRef DemangledCall, 25951fbc6b26SAleksandr Bezzubikov SPIRV::InstructionSet::InstructionSet Set, 25961fbc6b26SAleksandr Bezzubikov MachineIRBuilder &MIRBuilder, 25971fbc6b26SAleksandr Bezzubikov const Register OrigRet, const Type *OrigRetTy, 25981fbc6b26SAleksandr Bezzubikov const SmallVectorImpl<Register> &Args, 2599f61eb416SIlia Diachkov SPIRVGlobalRegistry *GR) { 2600f61eb416SIlia Diachkov LLVM_DEBUG(dbgs() << "Lowering builtin call: " << DemangledCall << "\n"); 2601f61eb416SIlia Diachkov 2602f61eb416SIlia Diachkov // Lookup the builtin in the TableGen records. 2603b5132b7dSVyacheslav Levytskyy SPIRVType *SpvType = GR->getSPIRVTypeForVReg(OrigRet); 2604b5132b7dSVyacheslav Levytskyy assert(SpvType && "Inconsistent return register: expected valid type info"); 2605f61eb416SIlia Diachkov std::unique_ptr<const IncomingCall> Call = 2606b5132b7dSVyacheslav Levytskyy lookupBuiltin(DemangledCall, Set, OrigRet, SpvType, Args); 2607f61eb416SIlia Diachkov 2608f61eb416SIlia Diachkov if (!Call) { 26095fb4a051SMichal Paszkowski LLVM_DEBUG(dbgs() << "Builtin record was not found!\n"); 26101ea9dd32SKazu Hirata return std::nullopt; 2611f61eb416SIlia Diachkov } 2612f61eb416SIlia Diachkov 2613f61eb416SIlia Diachkov // TODO: check if the provided args meet the builtin requirments. 2614f61eb416SIlia Diachkov assert(Args.size() >= Call->Builtin->MinNumArgs && 2615f61eb416SIlia Diachkov "Too few arguments to generate the builtin"); 26165fb4a051SMichal Paszkowski if (Call->Builtin->MaxNumArgs && Args.size() > Call->Builtin->MaxNumArgs) 26175fb4a051SMichal Paszkowski LLVM_DEBUG(dbgs() << "More arguments provided than required!\n"); 2618f61eb416SIlia Diachkov 2619f61eb416SIlia Diachkov // Match the builtin with implementation based on the grouping. 2620f61eb416SIlia Diachkov switch (Call->Builtin->Group) { 2621f61eb416SIlia Diachkov case SPIRV::Extended: 26221fbc6b26SAleksandr Bezzubikov return generateExtInst(Call.get(), MIRBuilder, GR); 2623f61eb416SIlia Diachkov case SPIRV::Relational: 26241fbc6b26SAleksandr Bezzubikov return generateRelationalInst(Call.get(), MIRBuilder, GR); 2625f61eb416SIlia Diachkov case SPIRV::Group: 26261fbc6b26SAleksandr Bezzubikov return generateGroupInst(Call.get(), MIRBuilder, GR); 2627f61eb416SIlia Diachkov case SPIRV::Variable: 26281fbc6b26SAleksandr Bezzubikov return generateBuiltinVar(Call.get(), MIRBuilder, GR); 2629f61eb416SIlia Diachkov case SPIRV::Atomic: 26301fbc6b26SAleksandr Bezzubikov return generateAtomicInst(Call.get(), MIRBuilder, GR); 2631925768eeSVyacheslav Levytskyy case SPIRV::AtomicFloating: 2632925768eeSVyacheslav Levytskyy return generateAtomicFloatingInst(Call.get(), MIRBuilder, GR); 2633f61eb416SIlia Diachkov case SPIRV::Barrier: 26341fbc6b26SAleksandr Bezzubikov return generateBarrierInst(Call.get(), MIRBuilder, GR); 263557520985SVyacheslav Levytskyy case SPIRV::CastToPtr: 263657520985SVyacheslav Levytskyy return generateCastToPtrInst(Call.get(), MIRBuilder); 2637f61eb416SIlia Diachkov case SPIRV::Dot: 26381fbc6b26SAleksandr Bezzubikov return generateDotOrFMulInst(Call.get(), MIRBuilder, GR); 2639f0eb9083SNathan Gauër case SPIRV::Wave: 2640f0eb9083SNathan Gauër return generateWaveInst(Call.get(), MIRBuilder, GR); 26418ac46d6bSVyacheslav Levytskyy case SPIRV::ICarryBorrow: 26428ac46d6bSVyacheslav Levytskyy return generateICarryBorrowInst(Call.get(), MIRBuilder, GR); 2643f61eb416SIlia Diachkov case SPIRV::GetQuery: 26441fbc6b26SAleksandr Bezzubikov return generateGetQueryInst(Call.get(), MIRBuilder, GR); 2645f61eb416SIlia Diachkov case SPIRV::ImageSizeQuery: 26461fbc6b26SAleksandr Bezzubikov return generateImageSizeQueryInst(Call.get(), MIRBuilder, GR); 2647f61eb416SIlia Diachkov case SPIRV::ImageMiscQuery: 26481fbc6b26SAleksandr Bezzubikov return generateImageMiscQueryInst(Call.get(), MIRBuilder, GR); 2649f61eb416SIlia Diachkov case SPIRV::ReadImage: 26501fbc6b26SAleksandr Bezzubikov return generateReadImageInst(DemangledCall, Call.get(), MIRBuilder, GR); 2651f61eb416SIlia Diachkov case SPIRV::WriteImage: 26521fbc6b26SAleksandr Bezzubikov return generateWriteImageInst(Call.get(), MIRBuilder, GR); 2653f61eb416SIlia Diachkov case SPIRV::SampleImage: 26541fbc6b26SAleksandr Bezzubikov return generateSampleImageInst(DemangledCall, Call.get(), MIRBuilder, GR); 2655f61eb416SIlia Diachkov case SPIRV::Select: 26561fbc6b26SAleksandr Bezzubikov return generateSelectInst(Call.get(), MIRBuilder); 265757f79371SVyacheslav Levytskyy case SPIRV::Construct: 265857f79371SVyacheslav Levytskyy return generateConstructInst(Call.get(), MIRBuilder, GR); 2659f61eb416SIlia Diachkov case SPIRV::SpecConstant: 26601fbc6b26SAleksandr Bezzubikov return generateSpecConstantInst(Call.get(), MIRBuilder, GR); 2661f61eb416SIlia Diachkov case SPIRV::Enqueue: 26621fbc6b26SAleksandr Bezzubikov return generateEnqueueInst(Call.get(), MIRBuilder, GR); 2663f61eb416SIlia Diachkov case SPIRV::AsyncCopy: 26641fbc6b26SAleksandr Bezzubikov return generateAsyncCopy(Call.get(), MIRBuilder, GR); 2665f61eb416SIlia Diachkov case SPIRV::Convert: 26661fbc6b26SAleksandr Bezzubikov return generateConvertInst(DemangledCall, Call.get(), MIRBuilder, GR); 2667f61eb416SIlia Diachkov case SPIRV::VectorLoadStore: 26681fbc6b26SAleksandr Bezzubikov return generateVectorLoadStoreInst(Call.get(), MIRBuilder, GR); 26690b0224bcSIlia Diachkov case SPIRV::LoadStore: 26700b0224bcSIlia Diachkov return generateLoadStoreInst(Call.get(), MIRBuilder, GR); 2671b221b973SVyacheslav Levytskyy case SPIRV::IntelSubgroups: 2672b221b973SVyacheslav Levytskyy return generateIntelSubgroupsInst(Call.get(), MIRBuilder, GR); 267366ebda46SVyacheslav Levytskyy case SPIRV::GroupUniform: 267466ebda46SVyacheslav Levytskyy return generateGroupUniformInst(Call.get(), MIRBuilder, GR); 267589c23f76SSven van Haastregt case SPIRV::KernelClock: 267689c23f76SSven van Haastregt return generateKernelClockInst(Call.get(), MIRBuilder, GR); 267757f79371SVyacheslav Levytskyy case SPIRV::CoopMatr: 267857f79371SVyacheslav Levytskyy return generateCoopMatrInst(Call.get(), MIRBuilder, GR); 2679f61eb416SIlia Diachkov } 26801fbc6b26SAleksandr Bezzubikov return false; 2681f61eb416SIlia Diachkov } 2682698c8001SIlia Diachkov 2683489db653SVyacheslav Levytskyy Type *parseBuiltinCallArgumentType(StringRef TypeStr, LLVMContext &Ctx) { 268443222bd3SMichal Paszkowski // Parse strings representing OpenCL builtin types. 268543222bd3SMichal Paszkowski if (hasBuiltinTypePrefix(TypeStr)) { 268643222bd3SMichal Paszkowski // OpenCL builtin types in demangled call strings have the following format: 268743222bd3SMichal Paszkowski // e.g. ocl_image2d_ro 2688e83adfe5SChris B [[maybe_unused]] bool IsOCLBuiltinType = TypeStr.consume_front("ocl_"); 268943222bd3SMichal Paszkowski assert(IsOCLBuiltinType && "Invalid OpenCL builtin prefix"); 269043222bd3SMichal Paszkowski 269143222bd3SMichal Paszkowski // Check if this is pointer to a builtin type and not just pointer 269243222bd3SMichal Paszkowski // representing a builtin type. In case it is a pointer to builtin type, 269343222bd3SMichal Paszkowski // this will require additional handling in the method calling 269443222bd3SMichal Paszkowski // parseBuiltinCallArgumentBaseType(...) as this function only retrieves the 269543222bd3SMichal Paszkowski // base types. 269643222bd3SMichal Paszkowski if (TypeStr.ends_with("*")) 26971ed1ec9aSVyacheslav Levytskyy TypeStr = TypeStr.slice(0, TypeStr.find_first_of(" *")); 269843222bd3SMichal Paszkowski 269943222bd3SMichal Paszkowski return parseBuiltinTypeNameToTargetExtType("opencl." + TypeStr.str() + "_t", 270043222bd3SMichal Paszkowski Ctx); 270143222bd3SMichal Paszkowski } 270243222bd3SMichal Paszkowski 270343222bd3SMichal Paszkowski // Parse type name in either "typeN" or "type vector[N]" format, where 270443222bd3SMichal Paszkowski // N is the number of elements of the vector. 270543222bd3SMichal Paszkowski Type *BaseType; 270643222bd3SMichal Paszkowski unsigned VecElts = 0; 270743222bd3SMichal Paszkowski 270843222bd3SMichal Paszkowski BaseType = parseBasicTypeName(TypeStr, Ctx); 270943222bd3SMichal Paszkowski if (!BaseType) 271043222bd3SMichal Paszkowski // Unable to recognize SPIRV type name. 271143222bd3SMichal Paszkowski return nullptr; 271243222bd3SMichal Paszkowski 271343222bd3SMichal Paszkowski // Handle "typeN*" or "type vector[N]*". 271443222bd3SMichal Paszkowski TypeStr.consume_back("*"); 271543222bd3SMichal Paszkowski 271643222bd3SMichal Paszkowski if (TypeStr.consume_front(" vector[")) 271743222bd3SMichal Paszkowski TypeStr = TypeStr.substr(0, TypeStr.find(']')); 271843222bd3SMichal Paszkowski 271943222bd3SMichal Paszkowski TypeStr.getAsInteger(10, VecElts); 272043222bd3SMichal Paszkowski if (VecElts > 0) 2721dbd00a59SVyacheslav Levytskyy BaseType = VectorType::get( 2722dbd00a59SVyacheslav Levytskyy BaseType->isVoidTy() ? Type::getInt8Ty(Ctx) : BaseType, VecElts, false); 272343222bd3SMichal Paszkowski 272443222bd3SMichal Paszkowski return BaseType; 272543222bd3SMichal Paszkowski } 272643222bd3SMichal Paszkowski 2727489db653SVyacheslav Levytskyy bool parseBuiltinTypeStr(SmallVector<StringRef, 10> &BuiltinArgsTypeStrs, 2728489db653SVyacheslav Levytskyy const StringRef DemangledCall, LLVMContext &Ctx) { 2729489db653SVyacheslav Levytskyy auto Pos1 = DemangledCall.find('('); 2730489db653SVyacheslav Levytskyy if (Pos1 == StringRef::npos) 2731489db653SVyacheslav Levytskyy return false; 2732489db653SVyacheslav Levytskyy auto Pos2 = DemangledCall.find(')'); 2733489db653SVyacheslav Levytskyy if (Pos2 == StringRef::npos || Pos1 > Pos2) 2734489db653SVyacheslav Levytskyy return false; 2735489db653SVyacheslav Levytskyy DemangledCall.slice(Pos1 + 1, Pos2) 2736489db653SVyacheslav Levytskyy .split(BuiltinArgsTypeStrs, ',', -1, false); 2737489db653SVyacheslav Levytskyy return true; 2738489db653SVyacheslav Levytskyy } 2739489db653SVyacheslav Levytskyy 2740489db653SVyacheslav Levytskyy Type *parseBuiltinCallArgumentBaseType(const StringRef DemangledCall, 2741489db653SVyacheslav Levytskyy unsigned ArgIdx, LLVMContext &Ctx) { 2742489db653SVyacheslav Levytskyy SmallVector<StringRef, 10> BuiltinArgsTypeStrs; 2743489db653SVyacheslav Levytskyy parseBuiltinTypeStr(BuiltinArgsTypeStrs, DemangledCall, Ctx); 2744489db653SVyacheslav Levytskyy if (ArgIdx >= BuiltinArgsTypeStrs.size()) 2745489db653SVyacheslav Levytskyy return nullptr; 2746489db653SVyacheslav Levytskyy StringRef TypeStr = BuiltinArgsTypeStrs[ArgIdx].trim(); 2747489db653SVyacheslav Levytskyy return parseBuiltinCallArgumentType(TypeStr, Ctx); 2748489db653SVyacheslav Levytskyy } 2749489db653SVyacheslav Levytskyy 27505ac69674SMichal Paszkowski struct BuiltinType { 2751698c8001SIlia Diachkov StringRef Name; 2752698c8001SIlia Diachkov uint32_t Opcode; 2753698c8001SIlia Diachkov }; 2754698c8001SIlia Diachkov 27555ac69674SMichal Paszkowski #define GET_BuiltinTypes_DECL 27565ac69674SMichal Paszkowski #define GET_BuiltinTypes_IMPL 2757698c8001SIlia Diachkov 27585ac69674SMichal Paszkowski struct OpenCLType { 2759698c8001SIlia Diachkov StringRef Name; 27605ac69674SMichal Paszkowski StringRef SpirvTypeLiteral; 2761698c8001SIlia Diachkov }; 2762698c8001SIlia Diachkov 27635ac69674SMichal Paszkowski #define GET_OpenCLTypes_DECL 27645ac69674SMichal Paszkowski #define GET_OpenCLTypes_IMPL 2765698c8001SIlia Diachkov 2766698c8001SIlia Diachkov #include "SPIRVGenTables.inc" 2767698c8001SIlia Diachkov } // namespace SPIRV 2768698c8001SIlia Diachkov 2769698c8001SIlia Diachkov //===----------------------------------------------------------------------===// 27705ac69674SMichal Paszkowski // Misc functions for parsing builtin types. 2771698c8001SIlia Diachkov //===----------------------------------------------------------------------===// 2772698c8001SIlia Diachkov 27735ac69674SMichal Paszkowski static Type *parseTypeString(const StringRef Name, LLVMContext &Context) { 2774395f9ce3SKazu Hirata if (Name.starts_with("void")) 27755ac69674SMichal Paszkowski return Type::getVoidTy(Context); 2776395f9ce3SKazu Hirata else if (Name.starts_with("int") || Name.starts_with("uint")) 27775ac69674SMichal Paszkowski return Type::getInt32Ty(Context); 2778395f9ce3SKazu Hirata else if (Name.starts_with("float")) 27795ac69674SMichal Paszkowski return Type::getFloatTy(Context); 2780395f9ce3SKazu Hirata else if (Name.starts_with("half")) 27815ac69674SMichal Paszkowski return Type::getHalfTy(Context); 2782925768eeSVyacheslav Levytskyy report_fatal_error("Unable to recognize type!"); 2783698c8001SIlia Diachkov } 2784698c8001SIlia Diachkov 2785698c8001SIlia Diachkov //===----------------------------------------------------------------------===// 2786698c8001SIlia Diachkov // Implementation functions for builtin types. 2787698c8001SIlia Diachkov //===----------------------------------------------------------------------===// 2788698c8001SIlia Diachkov 278920f650b2SMichal Paszkowski static SPIRVType *getNonParameterizedType(const TargetExtType *ExtensionType, 27905ac69674SMichal Paszkowski const SPIRV::BuiltinType *TypeRecord, 2791698c8001SIlia Diachkov MachineIRBuilder &MIRBuilder, 2792698c8001SIlia Diachkov SPIRVGlobalRegistry *GR) { 2793698c8001SIlia Diachkov unsigned Opcode = TypeRecord->Opcode; 2794698c8001SIlia Diachkov // Create or get an existing type from GlobalRegistry. 27955ac69674SMichal Paszkowski return GR->getOrCreateOpTypeByOpcode(ExtensionType, MIRBuilder, Opcode); 2796698c8001SIlia Diachkov } 2797698c8001SIlia Diachkov 27983544d200SIlia Diachkov static SPIRVType *getSamplerType(MachineIRBuilder &MIRBuilder, 2799698c8001SIlia Diachkov SPIRVGlobalRegistry *GR) { 2800698c8001SIlia Diachkov // Create or get an existing type from GlobalRegistry. 2801698c8001SIlia Diachkov return GR->getOrCreateOpTypeSampler(MIRBuilder); 2802698c8001SIlia Diachkov } 2803698c8001SIlia Diachkov 28045ac69674SMichal Paszkowski static SPIRVType *getPipeType(const TargetExtType *ExtensionType, 28053544d200SIlia Diachkov MachineIRBuilder &MIRBuilder, 28063544d200SIlia Diachkov SPIRVGlobalRegistry *GR) { 28075ac69674SMichal Paszkowski assert(ExtensionType->getNumIntParameters() == 1 && 28085ac69674SMichal Paszkowski "Invalid number of parameters for SPIR-V pipe builtin!"); 2809698c8001SIlia Diachkov // Create or get an existing type from GlobalRegistry. 28105ac69674SMichal Paszkowski return GR->getOrCreateOpTypePipe(MIRBuilder, 28115ac69674SMichal Paszkowski SPIRV::AccessQualifier::AccessQualifier( 28125ac69674SMichal Paszkowski ExtensionType->getIntParameter(0))); 2813698c8001SIlia Diachkov } 2814698c8001SIlia Diachkov 281557f79371SVyacheslav Levytskyy static SPIRVType *getCoopMatrType(const TargetExtType *ExtensionType, 281657f79371SVyacheslav Levytskyy MachineIRBuilder &MIRBuilder, 281757f79371SVyacheslav Levytskyy SPIRVGlobalRegistry *GR) { 281857f79371SVyacheslav Levytskyy assert(ExtensionType->getNumIntParameters() == 4 && 281957f79371SVyacheslav Levytskyy "Invalid number of parameters for SPIR-V coop matrices builtin!"); 282057f79371SVyacheslav Levytskyy assert(ExtensionType->getNumTypeParameters() == 1 && 282157f79371SVyacheslav Levytskyy "SPIR-V coop matrices builtin type must have a type parameter!"); 282257f79371SVyacheslav Levytskyy const SPIRVType *ElemType = 282357f79371SVyacheslav Levytskyy GR->getOrCreateSPIRVType(ExtensionType->getTypeParameter(0), MIRBuilder); 282457f79371SVyacheslav Levytskyy // Create or get an existing type from GlobalRegistry. 282557f79371SVyacheslav Levytskyy return GR->getOrCreateOpTypeCoopMatr( 282657f79371SVyacheslav Levytskyy MIRBuilder, ExtensionType, ElemType, ExtensionType->getIntParameter(0), 282757f79371SVyacheslav Levytskyy ExtensionType->getIntParameter(1), ExtensionType->getIntParameter(2), 282857f79371SVyacheslav Levytskyy ExtensionType->getIntParameter(3)); 282957f79371SVyacheslav Levytskyy } 283057f79371SVyacheslav Levytskyy 28313544d200SIlia Diachkov static SPIRVType * 28325ac69674SMichal Paszkowski getImageType(const TargetExtType *ExtensionType, 28335ac69674SMichal Paszkowski const SPIRV::AccessQualifier::AccessQualifier Qualifier, 2834698c8001SIlia Diachkov MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR) { 28355ac69674SMichal Paszkowski assert(ExtensionType->getNumTypeParameters() == 1 && 28365ac69674SMichal Paszkowski "SPIR-V image builtin type must have sampled type parameter!"); 28375ac69674SMichal Paszkowski const SPIRVType *SampledType = 28385ac69674SMichal Paszkowski GR->getOrCreateSPIRVType(ExtensionType->getTypeParameter(0), MIRBuilder); 28395114758bSSteven Perron assert((ExtensionType->getNumIntParameters() == 7 || 28405114758bSSteven Perron ExtensionType->getNumIntParameters() == 6) && 28415ac69674SMichal Paszkowski "Invalid number of parameters for SPIR-V image builtin!"); 28425114758bSSteven Perron 28435114758bSSteven Perron SPIRV::AccessQualifier::AccessQualifier accessQualifier = 28445114758bSSteven Perron SPIRV::AccessQualifier::None; 28455114758bSSteven Perron if (ExtensionType->getNumIntParameters() == 7) { 28465114758bSSteven Perron accessQualifier = Qualifier == SPIRV::AccessQualifier::WriteOnly 28475114758bSSteven Perron ? SPIRV::AccessQualifier::WriteOnly 28485114758bSSteven Perron : SPIRV::AccessQualifier::AccessQualifier( 28495114758bSSteven Perron ExtensionType->getIntParameter(6)); 28505114758bSSteven Perron } 28515114758bSSteven Perron 28525ac69674SMichal Paszkowski // Create or get an existing type from GlobalRegistry. 2853698c8001SIlia Diachkov return GR->getOrCreateOpTypeImage( 28545ac69674SMichal Paszkowski MIRBuilder, SampledType, 28555ac69674SMichal Paszkowski SPIRV::Dim::Dim(ExtensionType->getIntParameter(0)), 28565ac69674SMichal Paszkowski ExtensionType->getIntParameter(1), ExtensionType->getIntParameter(2), 28575ac69674SMichal Paszkowski ExtensionType->getIntParameter(3), ExtensionType->getIntParameter(4), 28585ac69674SMichal Paszkowski SPIRV::ImageFormat::ImageFormat(ExtensionType->getIntParameter(5)), 28595114758bSSteven Perron accessQualifier); 2860698c8001SIlia Diachkov } 2861698c8001SIlia Diachkov 28625ac69674SMichal Paszkowski static SPIRVType *getSampledImageType(const TargetExtType *OpaqueType, 2863698c8001SIlia Diachkov MachineIRBuilder &MIRBuilder, 2864698c8001SIlia Diachkov SPIRVGlobalRegistry *GR) { 28655ac69674SMichal Paszkowski SPIRVType *OpaqueImageType = getImageType( 28665ac69674SMichal Paszkowski OpaqueType, SPIRV::AccessQualifier::ReadOnly, MIRBuilder, GR); 28675ac69674SMichal Paszkowski // Create or get an existing type from GlobalRegistry. 28685ac69674SMichal Paszkowski return GR->getOrCreateOpTypeSampledImage(OpaqueImageType, MIRBuilder); 2869698c8001SIlia Diachkov } 2870698c8001SIlia Diachkov 2871698c8001SIlia Diachkov namespace SPIRV { 287243222bd3SMichal Paszkowski TargetExtType *parseBuiltinTypeNameToTargetExtType(std::string TypeName, 287343222bd3SMichal Paszkowski LLVMContext &Context) { 287481751905SMichal Paszkowski StringRef NameWithParameters = TypeName; 287581751905SMichal Paszkowski 287681751905SMichal Paszkowski // Pointers-to-opaque-structs representing OpenCL types are first translated 287781751905SMichal Paszkowski // to equivalent SPIR-V types. OpenCL builtin type names should have the 287881751905SMichal Paszkowski // following format: e.g. %opencl.event_t 2879395f9ce3SKazu Hirata if (NameWithParameters.starts_with("opencl.")) { 288081751905SMichal Paszkowski const SPIRV::OpenCLType *OCLTypeRecord = 288181751905SMichal Paszkowski SPIRV::lookupOpenCLType(NameWithParameters); 288281751905SMichal Paszkowski if (!OCLTypeRecord) 288381751905SMichal Paszkowski report_fatal_error("Missing TableGen record for OpenCL type: " + 288481751905SMichal Paszkowski NameWithParameters); 288581751905SMichal Paszkowski NameWithParameters = OCLTypeRecord->SpirvTypeLiteral; 288681751905SMichal Paszkowski // Continue with the SPIR-V builtin type... 288781751905SMichal Paszkowski } 288881751905SMichal Paszkowski 288981751905SMichal Paszkowski // Names of the opaque structs representing a SPIR-V builtins without 289081751905SMichal Paszkowski // parameters should have the following format: e.g. %spirv.Event 2891395f9ce3SKazu Hirata assert(NameWithParameters.starts_with("spirv.") && 289281751905SMichal Paszkowski "Unknown builtin opaque type!"); 289381751905SMichal Paszkowski 289481751905SMichal Paszkowski // Parameterized SPIR-V builtins names follow this format: 289581751905SMichal Paszkowski // e.g. %spirv.Image._void_1_0_0_0_0_0_0, %spirv.Pipe._0 28961daf2994SKazu Hirata if (!NameWithParameters.contains('_')) 289743222bd3SMichal Paszkowski return TargetExtType::get(Context, NameWithParameters); 289881751905SMichal Paszkowski 289981751905SMichal Paszkowski SmallVector<StringRef> Parameters; 290081751905SMichal Paszkowski unsigned BaseNameLength = NameWithParameters.find('_') - 1; 290181751905SMichal Paszkowski SplitString(NameWithParameters.substr(BaseNameLength + 1), Parameters, "_"); 290281751905SMichal Paszkowski 290381751905SMichal Paszkowski SmallVector<Type *, 1> TypeParameters; 290481751905SMichal Paszkowski bool HasTypeParameter = !isDigit(Parameters[0][0]); 290581751905SMichal Paszkowski if (HasTypeParameter) 290643222bd3SMichal Paszkowski TypeParameters.push_back(parseTypeString(Parameters[0], Context)); 290781751905SMichal Paszkowski SmallVector<unsigned> IntParameters; 290881751905SMichal Paszkowski for (unsigned i = HasTypeParameter ? 1 : 0; i < Parameters.size(); i++) { 290981751905SMichal Paszkowski unsigned IntParameter = 0; 291081751905SMichal Paszkowski bool ValidLiteral = !Parameters[i].getAsInteger(10, IntParameter); 2911b221b973SVyacheslav Levytskyy (void)ValidLiteral; 291281751905SMichal Paszkowski assert(ValidLiteral && 291381751905SMichal Paszkowski "Invalid format of SPIR-V builtin parameter literal!"); 291481751905SMichal Paszkowski IntParameters.push_back(IntParameter); 291581751905SMichal Paszkowski } 291643222bd3SMichal Paszkowski return TargetExtType::get(Context, 291781751905SMichal Paszkowski NameWithParameters.substr(0, BaseNameLength), 291881751905SMichal Paszkowski TypeParameters, IntParameters); 291981751905SMichal Paszkowski } 292081751905SMichal Paszkowski 29215ac69674SMichal Paszkowski SPIRVType *lowerBuiltinType(const Type *OpaqueType, 29224421b24fSIlia Diachkov SPIRV::AccessQualifier::AccessQualifier AccessQual, 2923698c8001SIlia Diachkov MachineIRBuilder &MIRBuilder, 2924698c8001SIlia Diachkov SPIRVGlobalRegistry *GR) { 29255ac69674SMichal Paszkowski // In LLVM IR, SPIR-V and OpenCL builtin types are represented as either 29265ac69674SMichal Paszkowski // target(...) target extension types or pointers-to-opaque-structs. The 29275ac69674SMichal Paszkowski // approach relying on structs is deprecated and works only in the non-opaque 29285ac69674SMichal Paszkowski // pointer mode (-opaque-pointers=0). 29295ac69674SMichal Paszkowski // In order to maintain compatibility with LLVM IR generated by older versions 29305ac69674SMichal Paszkowski // of Clang and LLVM/SPIR-V Translator, the pointers-to-opaque-structs are 29315ac69674SMichal Paszkowski // "translated" to target extension types. This translation is temporary and 29325ac69674SMichal Paszkowski // will be removed in the future release of LLVM. 29335ac69674SMichal Paszkowski const TargetExtType *BuiltinType = dyn_cast<TargetExtType>(OpaqueType); 29345ac69674SMichal Paszkowski if (!BuiltinType) 293581751905SMichal Paszkowski BuiltinType = parseBuiltinTypeNameToTargetExtType( 293643222bd3SMichal Paszkowski OpaqueType->getStructName().str(), MIRBuilder.getContext()); 29375ac69674SMichal Paszkowski 2938698c8001SIlia Diachkov unsigned NumStartingVRegs = MIRBuilder.getMRI()->getNumVirtRegs(); 2939698c8001SIlia Diachkov 29405ac69674SMichal Paszkowski const StringRef Name = BuiltinType->getName(); 2941698c8001SIlia Diachkov LLVM_DEBUG(dbgs() << "Lowering builtin type: " << Name << "\n"); 2942698c8001SIlia Diachkov 2943698c8001SIlia Diachkov // Lookup the demangled builtin type in the TableGen records. 29445ac69674SMichal Paszkowski const SPIRV::BuiltinType *TypeRecord = SPIRV::lookupBuiltinType(Name); 2945698c8001SIlia Diachkov if (!TypeRecord) 2946698c8001SIlia Diachkov report_fatal_error("Missing TableGen record for builtin type: " + Name); 2947698c8001SIlia Diachkov 2948698c8001SIlia Diachkov // "Lower" the BuiltinType into TargetType. The following get<...>Type methods 29495ac69674SMichal Paszkowski // use the implementation details from TableGen records or TargetExtType 29505ac69674SMichal Paszkowski // parameters to either create a new OpType<...> machine instruction or get an 29515ac69674SMichal Paszkowski // existing equivalent SPIRVType from GlobalRegistry. 2952698c8001SIlia Diachkov SPIRVType *TargetType; 2953698c8001SIlia Diachkov switch (TypeRecord->Opcode) { 2954698c8001SIlia Diachkov case SPIRV::OpTypeImage: 29555ac69674SMichal Paszkowski TargetType = getImageType(BuiltinType, AccessQual, MIRBuilder, GR); 2956698c8001SIlia Diachkov break; 2957698c8001SIlia Diachkov case SPIRV::OpTypePipe: 29585ac69674SMichal Paszkowski TargetType = getPipeType(BuiltinType, MIRBuilder, GR); 2959698c8001SIlia Diachkov break; 2960748922b3SIlia Diachkov case SPIRV::OpTypeDeviceEvent: 2961748922b3SIlia Diachkov TargetType = GR->getOrCreateOpTypeDeviceEvent(MIRBuilder); 2962748922b3SIlia Diachkov break; 2963698c8001SIlia Diachkov case SPIRV::OpTypeSampler: 2964698c8001SIlia Diachkov TargetType = getSamplerType(MIRBuilder, GR); 2965698c8001SIlia Diachkov break; 2966698c8001SIlia Diachkov case SPIRV::OpTypeSampledImage: 29675ac69674SMichal Paszkowski TargetType = getSampledImageType(BuiltinType, MIRBuilder, GR); 2968698c8001SIlia Diachkov break; 296957f79371SVyacheslav Levytskyy case SPIRV::OpTypeCooperativeMatrixKHR: 297057f79371SVyacheslav Levytskyy TargetType = getCoopMatrType(BuiltinType, MIRBuilder, GR); 297157f79371SVyacheslav Levytskyy break; 2972698c8001SIlia Diachkov default: 29735ac69674SMichal Paszkowski TargetType = 297420f650b2SMichal Paszkowski getNonParameterizedType(BuiltinType, TypeRecord, MIRBuilder, GR); 2975698c8001SIlia Diachkov break; 2976698c8001SIlia Diachkov } 2977698c8001SIlia Diachkov 2978698c8001SIlia Diachkov // Emit OpName instruction if a new OpType<...> instruction was added 2979698c8001SIlia Diachkov // (equivalent type was not found in GlobalRegistry). 2980698c8001SIlia Diachkov if (NumStartingVRegs < MIRBuilder.getMRI()->getNumVirtRegs()) 29815ac69674SMichal Paszkowski buildOpName(GR->getSPIRVTypeID(TargetType), Name, MIRBuilder); 2982698c8001SIlia Diachkov 2983698c8001SIlia Diachkov return TargetType; 2984698c8001SIlia Diachkov } 2985f61eb416SIlia Diachkov } // namespace SPIRV 2986f61eb416SIlia Diachkov } // namespace llvm 2987