Files
TheRock/compiler/spirv-llvm-translator/lib/SPIRV/SPIRVInternal.h
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

1186 lines
47 KiB
C++

//===- LLVMSPIRVInternal.h - SPIR-V internal header file -------*- C++ -*-===//
//
// The LLVM/SPIRV Translator
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal with the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimers.
// Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimers in the documentation
// and/or other materials provided with the distribution.
// Neither the names of Advanced Micro Devices, Inc., nor the names of its
// contributors may be used to endorse or promote products derived from this
// Software without specific prior written permission.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
// THE SOFTWARE.
//
//===----------------------------------------------------------------------===//
/// \file
///
/// This file declares classes and functions shared by SPIR-V reader/writer.
///
//===----------------------------------------------------------------------===//
#ifndef SPIRV_SPIRVINTERNAL_H
#define SPIRV_SPIRVINTERNAL_H
#include "NameMangleAPI.h"
#include "libSPIRV/SPIRVEnum.h"
#include "libSPIRV/SPIRVError.h"
#include "libSPIRV/SPIRVNameMapEnum.h"
#include "libSPIRV/SPIRVType.h"
#include "libSPIRV/SPIRVUtil.h"
#include "LLVMSPIRVLib.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/TypedPointerType.h"
#include <functional>
#include <utility>
using namespace SPIRV;
using namespace llvm;
namespace llvm {
class IntrinsicInst;
class IRBuilderBase;
} // namespace llvm
namespace SPIRV {
/// The LLVM/SPIR-V translator version used to fill the lower 16 bits of the
/// generator's magic number in the generated SPIR-V module.
/// This number should be bumped up whenever the generated SPIR-V changes.
const static unsigned short KTranslatorVer = 14;
class SPIRVOpaqueType;
typedef SPIRVMap<std::string, Op, SPIRVOpaqueType> SPIRVOpaqueTypeOpCodeMap;
// Ad hoc function used by LLVM/SPIRV converter for type casting
#define SPCV_CAST "spcv.cast"
#define LLVM_MEMCPY "llvm.memcpy"
// The name of function generated by Clang to initialize sampler(which is
// opaqueue type) by 32-bit integer. The name is taken from
// CodeGenModule::createOpenCLIntToSamplerConversion().
#define SAMPLER_INIT "__translate_sampler_initializer"
template <> inline void SPIRVMap<unsigned, Op>::init() {
#define _SPIRV_OP(x, y) add(Instruction::x, Op##y);
/* Casts */
_SPIRV_OP(ZExt, UConvert)
_SPIRV_OP(SExt, SConvert)
_SPIRV_OP(Trunc, UConvert)
_SPIRV_OP(FPToUI, ConvertFToU)
_SPIRV_OP(FPToSI, ConvertFToS)
_SPIRV_OP(UIToFP, ConvertUToF)
_SPIRV_OP(SIToFP, ConvertSToF)
_SPIRV_OP(FPTrunc, FConvert)
_SPIRV_OP(FPExt, FConvert)
_SPIRV_OP(PtrToInt, ConvertPtrToU)
_SPIRV_OP(IntToPtr, ConvertUToPtr)
_SPIRV_OP(BitCast, Bitcast)
_SPIRV_OP(AddrSpaceCast, GenericCastToPtr)
_SPIRV_OP(GetElementPtr, AccessChain)
_SPIRV_OP(FNeg, FNegate)
/*Binary*/
_SPIRV_OP(And, BitwiseAnd)
_SPIRV_OP(Or, BitwiseOr)
_SPIRV_OP(Xor, BitwiseXor)
_SPIRV_OP(Add, IAdd)
_SPIRV_OP(FAdd, FAdd)
_SPIRV_OP(Sub, ISub)
_SPIRV_OP(FSub, FSub)
_SPIRV_OP(Mul, IMul)
_SPIRV_OP(FMul, FMul)
_SPIRV_OP(UDiv, UDiv)
_SPIRV_OP(SDiv, SDiv)
_SPIRV_OP(FDiv, FDiv)
_SPIRV_OP(SRem, SRem)
_SPIRV_OP(FRem, FRem)
_SPIRV_OP(URem, UMod)
_SPIRV_OP(Shl, ShiftLeftLogical)
_SPIRV_OP(LShr, ShiftRightLogical)
_SPIRV_OP(AShr, ShiftRightArithmetic)
#undef _SPIRV_OP
}
typedef SPIRVMap<unsigned, Op> OpCodeMap;
template <> inline void SPIRVMap<CmpInst::Predicate, Op>::init() {
#define _SPIRV_OP(x, y) add(CmpInst::x, Op##y);
_SPIRV_OP(FCMP_OEQ, FOrdEqual)
_SPIRV_OP(FCMP_OGT, FOrdGreaterThan)
_SPIRV_OP(FCMP_OGE, FOrdGreaterThanEqual)
_SPIRV_OP(FCMP_OLT, FOrdLessThan)
_SPIRV_OP(FCMP_OLE, FOrdLessThanEqual)
_SPIRV_OP(FCMP_ONE, FOrdNotEqual)
_SPIRV_OP(FCMP_ORD, Ordered)
_SPIRV_OP(FCMP_UNO, Unordered)
_SPIRV_OP(FCMP_UEQ, FUnordEqual)
_SPIRV_OP(FCMP_UGT, FUnordGreaterThan)
_SPIRV_OP(FCMP_UGE, FUnordGreaterThanEqual)
_SPIRV_OP(FCMP_ULT, FUnordLessThan)
_SPIRV_OP(FCMP_ULE, FUnordLessThanEqual)
_SPIRV_OP(FCMP_UNE, FUnordNotEqual)
_SPIRV_OP(ICMP_EQ, IEqual)
_SPIRV_OP(ICMP_NE, INotEqual)
_SPIRV_OP(ICMP_UGT, UGreaterThan)
_SPIRV_OP(ICMP_UGE, UGreaterThanEqual)
_SPIRV_OP(ICMP_ULT, ULessThan)
_SPIRV_OP(ICMP_ULE, ULessThanEqual)
_SPIRV_OP(ICMP_SGT, SGreaterThan)
_SPIRV_OP(ICMP_SGE, SGreaterThanEqual)
_SPIRV_OP(ICMP_SLT, SLessThan)
_SPIRV_OP(ICMP_SLE, SLessThanEqual)
#undef _SPIRV_OP
}
typedef SPIRVMap<CmpInst::Predicate, Op> CmpMap;
class IntBoolOpMapId;
template <> inline void SPIRVMap<Op, Op, IntBoolOpMapId>::init() {
add(OpNot, OpLogicalNot);
add(OpBitwiseAnd, OpLogicalAnd);
add(OpBitwiseOr, OpLogicalOr);
add(OpBitwiseXor, OpLogicalNotEqual);
add(OpIEqual, OpLogicalEqual);
add(OpINotEqual, OpLogicalNotEqual);
}
typedef SPIRVMap<Op, Op, IntBoolOpMapId> IntBoolOpMap;
#define SPIR_TARGETTRIPLE32 "spir-unknown-unknown"
#define SPIR_TARGETTRIPLE64 "spir64-unknown-unknown"
#define SPIR_DATALAYOUT32 \
"e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32" \
"-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32" \
"-v32:32:32-v48:64:64-v64:64:64-v96:128:128" \
"-v128:128:128-v192:256:256-v256:256:256" \
"-v512:512:512-v1024:1024:1024"
#define SPIR_DATALAYOUT64 \
"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32" \
"-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32" \
"-v32:32:32-v48:64:64-v64:64:64-v96:128:128" \
"-v128:128:128-v192:256:256-v256:256:256" \
"-v512:512:512-v1024:1024:1024"
template <> inline void SPIRVMap<SPIRAddressSpace, std::string>::init() {
add(SPIRAS_Private, "Private");
add(SPIRAS_Global, "Global");
add(SPIRAS_Constant, "Constant");
add(SPIRAS_Local, "Local");
add(SPIRAS_Generic, "Generic");
add(SPIRAS_Input, "Input");
add(SPIRAS_CodeSectionINTEL, "CodeSectionINTEL");
add(SPIRAS_GlobalDevice, "GlobalDevice");
add(SPIRAS_GlobalHost, "GlobalHost");
}
typedef SPIRVMap<SPIRAddressSpace, SPIRVStorageClassKind>
SPIRAddrSpaceCapitalizedNameMap;
template <>
inline void SPIRVMap<SPIRAddressSpace, SPIRVStorageClassKind>::init() {
add(SPIRAS_Private, StorageClassFunction);
add(SPIRAS_Global, StorageClassCrossWorkgroup);
add(SPIRAS_Constant, StorageClassUniformConstant);
add(SPIRAS_Local, StorageClassWorkgroup);
add(SPIRAS_Generic, StorageClassGeneric);
add(SPIRAS_Input, StorageClassInput);
add(SPIRAS_GlobalDevice, StorageClassDeviceOnlyINTEL);
add(SPIRAS_GlobalHost, StorageClassHostOnlyINTEL);
add(SPIRAS_CodeSectionINTEL, StorageClassCodeSectionINTEL);
}
typedef SPIRVMap<SPIRAddressSpace, SPIRVStorageClassKind> SPIRSPIRVAddrSpaceMap;
// Maps OCL builtin function to SPIRV builtin variable.
template <>
inline void SPIRVMap<std::string, SPIRVAccessQualifierKind>::init() {
add("read_only", AccessQualifierReadOnly);
add("write_only", AccessQualifierWriteOnly);
add("read_write", AccessQualifierReadWrite);
}
typedef SPIRVMap<std::string, SPIRVAccessQualifierKind>
SPIRSPIRVAccessQualifierMap;
template <>
inline void SPIRVMap<Attribute::AttrKind, SPIRVFuncParamAttrKind>::init() {
add(Attribute::ZExt, FunctionParameterAttributeZext);
add(Attribute::SExt, FunctionParameterAttributeSext);
add(Attribute::ByVal, FunctionParameterAttributeByVal);
add(Attribute::StructRet, FunctionParameterAttributeSret);
add(Attribute::NoAlias, FunctionParameterAttributeNoAlias);
add(Attribute::Captures, FunctionParameterAttributeNoCapture);
add(Attribute::ReadOnly, FunctionParameterAttributeNoWrite);
add(Attribute::ReadNone, FunctionParameterAttributeNoReadWrite);
}
typedef SPIRVMap<Attribute::AttrKind, SPIRVFuncParamAttrKind>
SPIRSPIRVFuncParamAttrMap;
template <>
inline void
SPIRVMap<Attribute::AttrKind, SPIRVFunctionControlMaskKind>::init() {
add(Attribute::AlwaysInline, FunctionControlInlineMask);
add(Attribute::NoInline, FunctionControlDontInlineMask);
add(Attribute::OptimizeNone, FunctionControlOptNoneEXTMask);
}
typedef SPIRVMap<Attribute::AttrKind, SPIRVFunctionControlMaskKind>
SPIRSPIRVFuncCtlMaskMap;
class SPIRVExtSetShortName;
template <>
inline void
SPIRVMap<SPIRVExtInstSetKind, std::string, SPIRVExtSetShortName>::init() {
add(SPIRVEIS_OpenCL, "ocl");
}
typedef SPIRVMap<SPIRVExtInstSetKind, std::string, SPIRVExtSetShortName>
SPIRVExtSetShortNameMap;
#define SPIR_MD_COMPILER_OPTIONS "opencl.compiler.options"
#define SPIR_MD_KERNEL_ARG_ADDR_SPACE "kernel_arg_addr_space"
#define SPIR_MD_KERNEL_ARG_ACCESS_QUAL "kernel_arg_access_qual"
#define SPIR_MD_KERNEL_ARG_TYPE "kernel_arg_type"
#define SPIR_MD_KERNEL_ARG_BASE_TYPE "kernel_arg_base_type"
#define SPIR_MD_KERNEL_ARG_TYPE_QUAL "kernel_arg_type_qual"
#define SPIR_MD_KERNEL_ARG_NAME "kernel_arg_name"
#define SPIRV_MD_PARAMETER_DECORATIONS "spirv.ParameterDecorations"
#define SPIRV_MD_DECORATIONS "spirv.Decorations"
#define SPIRV_MD_INTEL_CACHE_DECORATIONS "spirv.DecorationCacheControlINTEL"
#define OCL_TYPE_NAME_SAMPLER_T "sampler_t"
#define SPIR_TYPE_NAME_EVENT_T "opencl.event_t"
#define SPIR_TYPE_NAME_CLK_EVENT_T "opencl.clk_event_t"
#define SPIR_TYPE_NAME_BLOCK_T "opencl.block"
#define SPIR_INTRINSIC_BLOCK_BIND "spir_block_bind"
#define SPIR_INTRINSIC_GET_BLOCK_INVOKE "spir_get_block_invoke"
#define SPIR_INTRINSIC_GET_BLOCK_CONTEXT "spir_get_block_context"
#define SPIR_TEMP_NAME_PREFIX_BLOCK "block"
#define SPIR_TEMP_NAME_PREFIX_CALL "call"
namespace kLLVMTypeName {
const static char StructPrefix[] = "struct.";
} // namespace kLLVMTypeName
namespace kSPIRVImageSampledTypeName {
const static char Float[] = "float";
const static char Half[] = "half";
const static char Int[] = "int";
const static char UInt[] = "uint";
const static char Long[] = "long";
const static char ULong[] = "ulong";
const static char Void[] = "void";
} // namespace kSPIRVImageSampledTypeName
namespace kSPIRVTypeName {
const static char Delimiter = '.';
const static char DeviceEvent[] = "DeviceEvent";
const static char Event[] = "Event";
const static char Image[] = "Image";
const static char Pipe[] = "Pipe";
const static char PostfixDelim = '_';
const static char Prefix[] = "spirv";
const static char PrefixAndDelim[] = "spirv.";
const static char Queue[] = "Queue";
const static char ReserveId[] = "ReserveId";
const static char SampledImg[] = "SampledImage";
const static char Sampler[] = "Sampler";
const static char ConstantSampler[] = "ConstantSampler";
const static char PipeStorage[] = "PipeStorage";
const static char ConstantPipeStorage[] = "ConstantPipeStorage";
const static char VmeImageINTEL[] = "VmeImageINTEL";
const static char CooperativeMatrixKHR[] = "CooperativeMatrixKHR";
const static char BufferSurfaceINTEL[] = "BufferSurfaceINTEL";
} // namespace kSPIRVTypeName
namespace kSPR2TypeName {
const static char Delimiter = '.';
const static char OCLPrefix[] = "opencl.";
const static char ImagePrefix[] = "opencl.image";
const static char PipeRO[] = "opencl.pipe_ro_t";
const static char PipeWO[] = "opencl.pipe_wo_t";
const static char Sampler[] = "opencl.sampler_t";
const static char Event[] = "opencl.event_t";
} // namespace kSPR2TypeName
namespace kAccessQualName {
const static char ReadOnly[] = "read_only";
const static char WriteOnly[] = "write_only";
const static char ReadWrite[] = "read_write";
} // namespace kAccessQualName
namespace kAccessQualPostfix {
const static char ReadOnly[] = "_ro";
const static char WriteOnly[] = "_wo";
const static char ReadWrite[] = "_rw";
const static char Type[] = "_t";
} // namespace kAccessQualPostfix
namespace kMangledName {
const static char Sampler[] = "11ocl_sampler";
const static char AtomicPrefixIncoming[] = "U7_Atomic";
const static char AtomicPrefixInternal[] = "atomic_";
} // namespace kMangledName
namespace kSPIRVName {
const static char GroupPrefix[] = "group_";
const static char GroupNonUniformPrefix[] = "group_non_uniform_";
const static char ClusteredPrefix[] = "clustered_";
const static char Prefix[] = "__spirv_";
const static char Postfix[] = "__";
const static char ImageQuerySize[] = "ImageQuerySize";
const static char ImageQuerySizeLod[] = "ImageQuerySizeLod";
const static char ImageSampleExplicitLod[] = "ImageSampleExplicitLod";
const static char ReservedPrefix[] = "reserved_";
const static char SampledImage[] = "SampledImage";
const static char TempSampledImage[] = "TempSampledImage";
const static char TranslateOCLMemOrder[] = "__translate_ocl_memory_order";
const static char TranslateOCLMemScope[] = "__translate_ocl_memory_scope";
const static char TranslateSPIRVMemOrder[] = "__translate_spirv_memory_order";
const static char TranslateSPIRVMemScope[] = "__translate_spirv_memory_scope";
const static char TranslateSPIRVMemFence[] = "__translate_spirv_memory_fence";
const static char EntrypointPrefix[] = "__spirv_entry_";
const static char ConvertHandleToImageINTEL[] = "ConvertHandleToImageINTEL";
const static char ConvertHandleToSamplerINTEL[] = "ConvertHandleToSamplerINTEL";
const static char ConvertHandleToSampledImageINTEL[] =
"ConvertHandleToSampledImageINTEL";
const static char InternalBuiltinPrefix[] = "__builtin_spirv_";
} // namespace kSPIRVName
namespace kSPIRVPostfix {
const static char ToGlobal[] = "ToGlobal";
const static char ToLocal[] = "ToLocal";
const static char ToPrivate[] = "ToPrivate";
const static char Sat[] = "sat";
const static char Rtz[] = "rtz";
const static char Rte[] = "rte";
const static char Rtp[] = "rtp";
const static char Rtn[] = "rtn";
const static char Rt[] = "rt";
const static char Return[] = "R";
const static char Divider[] = "_";
/// Divider between extended instruction name and postfix
const static char ExtDivider[] = "__";
} // namespace kSPIRVPostfix
namespace kSPIRVMD {
const static char Capability[] = "spirv.Capability";
const static char EntryPoint[] = "spirv.EntryPoint";
const static char ExecutionMode[] = "spirv.ExecutionMode";
const static char Extension[] = "spirv.Extension";
const static char Generator[] = "spirv.Generator";
const static char Source[] = "spirv.Source";
const static char SourceExtension[] = "spirv.SourceExtension";
const static char MemoryModel[] = "spirv.MemoryModel";
} // namespace kSPIRVMD
namespace kSPIR2MD {
const static char Extensions[] = "opencl.used.extensions";
const static char FPContract[] = "opencl.enable.FP_CONTRACT";
const static char OCLVer[] = "opencl.ocl.version";
const static char OCLCXXVer[] = "opencl.cxx.version";
const static char OptFeatures[] = "opencl.used.optional.core.features";
const static char SPIRVer[] = "opencl.spir.version";
const static char VecTyHint[] = "vec_type_hint";
const static char WGSize[] = "reqd_work_group_size";
const static char WGSizeHint[] = "work_group_size_hint";
const static char SubgroupSize[] = "intel_reqd_sub_group_size";
const static char MaxWGSize[] = "max_work_group_size";
const static char NoGlobalOffset[] = "no_global_work_offset";
const static char MaxWGDim[] = "max_global_work_dim";
const static char NumSIMD[] = "num_simd_work_items";
const static char StallEnable[] = "stall_enable";
const static char StallFree[] = "stall_free";
const static char FmaxMhz[] = "scheduler_target_fmax_mhz";
const static char LoopFuse[] = "loop_fuse";
const static char PreferDSP[] = "prefer_dsp";
const static char PropDSPPref[] = "propagate_dsp_preference";
const static char InitiationInterval[] = "initiation_interval";
const static char MaxConcurrency[] = "max_concurrency";
const static char PipelineKernel[] = "pipeline_kernel";
const static char IntelFPGAIPInterface[] = "ip_interface";
} // namespace kSPIR2MD
enum Spir2SamplerKind {
CLK_ADDRESS_NONE = 0x0000,
CLK_ADDRESS_CLAMP = 0x0004,
CLK_ADDRESS_CLAMP_TO_EDGE = 0x0002,
CLK_ADDRESS_REPEAT = 0x0006,
CLK_ADDRESS_MIRRORED_REPEAT = 0x0008,
CLK_NORMALIZED_COORDS_FALSE = 0x0000,
CLK_NORMALIZED_COORDS_TRUE = 0x0001,
CLK_FILTER_NEAREST = 0x0010,
CLK_FILTER_LINEAR = 0x0020,
};
/// Additional information for mangling a function argument type.
struct BuiltinArgTypeMangleInfo {
bool IsSigned;
bool IsVoidPtr;
bool IsEnum;
bool IsSampler;
bool IsAtomic;
bool IsLocalArgBlock;
SPIR::TypePrimitiveEnum Enum;
unsigned Attr;
Type *PointerTy;
BuiltinArgTypeMangleInfo()
: IsSigned(true), IsVoidPtr(false), IsEnum(false), IsSampler(false),
IsAtomic(false), IsLocalArgBlock(false), Enum(SPIR::PRIMITIVE_NONE),
Attr(0), PointerTy(nullptr) {}
};
/// Information for mangling builtin function.
class BuiltinFuncMangleInfo {
public:
/// Translate builtin function name and set
/// argument attributes and unsigned args.
BuiltinFuncMangleInfo(const std::string &UniqName = "")
: VarArgIdx(-1), DontMangle(false) {
if (!UniqName.empty())
init(UniqName);
}
virtual ~BuiltinFuncMangleInfo() {}
const std::string &getUnmangledName() const { return UnmangledName; }
void addUnsignedArg(int Ndx) {
if (Ndx == -1)
return addUnsignedArgs(0, 10); // 10 is enough for everybody, right?
getTypeMangleInfo(Ndx).IsSigned = false;
}
void addUnsignedArgs(int StartNdx, int StopNdx) {
assert(StartNdx < StopNdx && "wrong parameters");
for (int I = StartNdx; I <= StopNdx; ++I)
addUnsignedArg(I);
}
void addVoidPtrArg(unsigned Ndx) { getTypeMangleInfo(Ndx).IsVoidPtr = true; }
void addSamplerArg(unsigned Ndx) { getTypeMangleInfo(Ndx).IsSampler = true; }
void addAtomicArg(unsigned Ndx) { getTypeMangleInfo(Ndx).IsAtomic = true; }
void setLocalArgBlock(unsigned Ndx) {
getTypeMangleInfo(Ndx).IsLocalArgBlock = true;
}
void setEnumArg(unsigned Ndx, SPIR::TypePrimitiveEnum Enum) {
auto &Info = getTypeMangleInfo(Ndx);
Info.IsEnum = true;
Info.Enum = Enum;
}
void setArgAttr(unsigned Ndx, unsigned Attr) {
getTypeMangleInfo(Ndx).Attr = Attr;
}
void setVarArg(int Ndx) {
assert(0 <= Ndx && "it is not allowed to set less than zero index");
VarArgIdx = Ndx;
}
void setAsDontMangle() { DontMangle = true; }
bool avoidMangling() { return DontMangle; }
// get ellipsis index, single ellipsis at the end of the function is possible
// only return value < 0 if none
int getVarArg() const { return VarArgIdx; }
BuiltinArgTypeMangleInfo &getTypeMangleInfo(unsigned Ndx) {
while (Ndx >= ArgInfo.size())
ArgInfo.emplace_back();
BuiltinArgTypeMangleInfo &Info = ArgInfo[Ndx];
return Info;
}
virtual void init(StringRef UniqUnmangledName) {
UnmangledName = UniqUnmangledName.str();
}
virtual bool isOpenCL() const { return false; }
protected:
std::string UnmangledName;
std::vector<BuiltinArgTypeMangleInfo> ArgInfo;
int VarArgIdx; // index of ellipsis argument, idx < 0 if none
private:
bool DontMangle; // clang doesn't apply mangling for some builtin functions
// (i.e. enqueue_kernel)
};
/// \returns a vector of types for a collection of values.
template <class T> std::vector<Type *> getTypes(llvm::ArrayRef<T> V) {
std::vector<Type *> Tys;
for (auto &I : V)
Tys.push_back(I->getType());
return Tys;
}
/// Move elements of std::vector from [begin, end) to target.
template <typename T>
void move(std::vector<T> &V, size_t Begin, size_t End, size_t Target) {
assert(Begin < End && End <= V.size() && Target <= V.size() &&
!(Begin < Target && Target < End));
if (Begin <= Target && Target <= End)
return;
auto B = V.begin() + Begin, E = V.begin() + End;
if (Target > V.size())
Target = V.size();
if (Target > End)
Target -= (End - Begin);
std::vector<T> Segment(B, E);
V.erase(B, E);
V.insert(V.begin() + Target, Segment.begin(), Segment.end());
}
/// Find position of first pointer type value in a vector.
template <typename Container>
inline unsigned findFirstPtr(const Container &Args) {
auto PtArg = std::find_if(Args.begin(), Args.end(), [](Value *V) {
return V->getType()->isPointerTy();
});
return PtArg - Args.begin();
}
// Utility function to check if a type is a TypedPointerType
inline bool isTypedPointerType(llvm::Type *Ty) {
return llvm::isa<llvm::TypedPointerType>(Ty);
}
template <typename Container>
inline unsigned findFirstPtrType(const Container &Args) {
auto PtArg = std::find_if(Args.begin(), Args.end(), [](Type *T) {
return T->isPointerTy() || isTypedPointerType(T);
});
return PtArg - Args.begin();
}
bool isSupportedTriple(Triple T);
void removeFnAttr(CallInst *Call, Attribute::AttrKind Attr);
void addFnAttr(CallInst *Call, Attribute::AttrKind Attr);
void saveLLVMModule(Module *M, const std::string &OutputFile);
std::string mapLLVMTypeToOCLType(const Type *Ty, bool Signed,
Type *PointerElementType = nullptr);
SPIRVDecorate *mapPostfixToDecorate(StringRef Postfix, SPIRVEntry *Target);
/// Return vector V extended with poison elements to match the number of
/// components of NewType.
Value *extendVector(Value *V, FixedVectorType *NewType, IRBuilderBase &Builder);
/// Add decorations to a SPIR-V entry.
/// \param Decs Each string is a postfix without _ at the beginning.
SPIRVValue *addDecorations(SPIRVValue *Target,
const SmallVectorImpl<std::string> &Decs);
StructType *getOrCreateOpaqueStructType(Module *M, StringRef Name);
void getFunctionTypeParameterTypes(llvm::FunctionType *FT,
std::vector<Type *> &ArgTys);
Function *getOrCreateFunction(Module *M, Type *RetTy, ArrayRef<Type *> ArgTypes,
StringRef Name,
BuiltinFuncMangleInfo *Mangle = nullptr,
AttributeList *Attrs = nullptr,
bool TakeName = true);
/// Get function call arguments.
/// \param Start Starting index.
/// \param End Ending index.
std::vector<Value *> getArguments(CallInst *CI, unsigned Start = 0,
unsigned End = 0);
/// Get constant function call argument as an integer.
/// \param I argument index.
uint64_t getArgAsInt(CallInst *CI, unsigned I);
/// Get constant function call argument as type \param T.
/// \param I argument index.
template <typename T> T getArgAs(CallInst *CI, unsigned I) {
return static_cast<T>(getArgAsInt(CI, I));
}
/// Get constant function call argument as a Scope enum.
/// \param I argument index.
Scope getArgAsScope(CallInst *CI, unsigned I);
/// Check if a type is OCL image type.
/// \return type name without "opencl." prefix.
bool isOCLImageType(llvm::Type *Ty, StringRef *Name = nullptr);
/// \param BaseTyName is the type name as in spirv.BaseTyName.Postfixes
/// \param Postfix contains postfixes extracted from the SPIR-V image
/// type name as spirv.BaseTyName.Postfixes.
bool isSPIRVStructType(llvm::Type *Ty, StringRef BaseTyName,
StringRef *Postfix = 0);
bool isSYCLHalfType(llvm::Type *Ty);
bool isSYCLBfloat16Type(llvm::Type *Ty);
/// Check if a function has decorated name as __spirv_{Name}_
/// and get the original name.
bool isDecoratedSPIRVFunc(const Function *F, StringRef &UndecName);
std::string prefixSPIRVName(const std::string &S);
StringRef dePrefixSPIRVName(StringRef R, SmallVectorImpl<StringRef> &Postfix);
/// Get a canonical function name for a SPIR-V op code.
std::string getSPIRVFuncName(Op OC, StringRef PostFix = "");
std::string getSPIRVFuncName(Op OC, const Type *PRetTy, bool IsSigned = false,
Type *PointerElementType = nullptr);
std::string getSPIRVFuncName(SPIRVBuiltinVariableKind BVKind);
/// Get a canonical function name for a SPIR-V extended instruction
std::string getSPIRVExtFuncName(SPIRVExtInstSetKind Set, unsigned ExtOp,
StringRef PostFix = "");
/// Get SPIR-V op code given the canonical function name.
/// Assume \param Name is either IA64 mangled or unmangled, and the unmangled
/// name takes the __spirv_{OpName}_{Postfixes} format.
/// \return op code if the unmangled function name is a valid op code name,
/// otherwise return OpNop.
/// \param Dec contains decorations decoded from function name if it is
/// not nullptr.
Op getSPIRVFuncOC(StringRef Name, SmallVectorImpl<std::string> *Dec = nullptr);
/// Get SPIR-V builtin variable enum given the canonical builtin name
/// Assume \param Name is in format __spirv_BuiltIn{Name}
/// \return false if \param Name is not a valid builtin name.
bool getSPIRVBuiltin(const std::string &Name, spv::BuiltIn &Builtin);
/// \param Name LLVM function name
/// \param DemangledName demangled name of the OpenCL built-in function
/// \returns true if Name is the name of the OpenCL built-in function,
/// false for other functions
bool oclIsBuiltin(StringRef Name, StringRef &DemangledName, bool IsCpp = false);
/// Check if a function returns void
bool isVoidFuncTy(FunctionType *FT);
/// \returns true if function \p F has array type argument.
bool hasArrayArg(Function *F);
/// Mutates function call instruction by changing the arguments.
/// \param ArgMutate mutates the function arguments.
/// \return mutated call instruction.
CallInst *mutateCallInst(
Module *M, CallInst *CI,
std::function<std::string(CallInst *, std::vector<Value *> &)> ArgMutate,
BuiltinFuncMangleInfo *Mangle = nullptr, AttributeList *Attrs = nullptr,
bool TakeName = false);
/// Mutates function call instruction by changing the arguments and return
/// value.
/// \param ArgMutate mutates the function arguments.
/// \param RetMutate mutates the return value.
/// \return mutated instruction.
Instruction *mutateCallInst(
Module *M, CallInst *CI,
std::function<std::string(CallInst *, std::vector<Value *> &, Type *&RetTy)>
ArgMutate,
std::function<Instruction *(CallInst *)> RetMutate,
BuiltinFuncMangleInfo *Mangle = nullptr, AttributeList *Attrs = nullptr,
bool TakeName = false);
/// Mutate function by change the arguments.
/// \param ArgMutate mutates the function arguments.
/// \param TakeName Take the original function's name if a new function with
/// different type needs to be created.
void mutateFunction(
Function *F,
std::function<std::string(CallInst *, std::vector<Value *> &)> ArgMutate,
BuiltinFuncMangleInfo *Mangle = nullptr, AttributeList *Attrs = nullptr,
bool TakeName = true);
/// Mutate function by change the arguments & the return type.
/// \param ArgMutate mutates the function arguments.
/// \param RetMutate mutates the function return value.
/// \param TakeName Take the original function's name if a new function with
/// different type needs to be created.
void mutateFunction(
Function *F,
std::function<std::string(CallInst *, std::vector<Value *> &, Type *&RetTy)>
ArgMutate,
std::function<Instruction *(CallInst *)> RetMutate,
BuiltinFuncMangleInfo *Mangle = nullptr, AttributeList *Attrs = nullptr,
bool TakeName = true);
/// Add a call instruction at \p Pos.
CallInst *addCallInst(Module *M, StringRef FuncName, Type *RetTy,
ArrayRef<Value *> Args, AttributeList *Attrs,
Instruction *Pos, BuiltinFuncMangleInfo *Mangle = nullptr,
StringRef InstName = SPIR_TEMP_NAME_PREFIX_CALL,
bool TakeFuncName = true);
/// Check if an LLVM type is spirv.CooperativeMatrixKHR.
bool isLLVMCooperativeMatrixType(llvm::Type *Ty);
/// Add a call instruction for SPIR-V builtin function.
CallInst *addCallInstSPIRV(Module *M, StringRef FuncName, Type *RetTy,
ArrayRef<Value *> Args, AttributeList *Attrs,
ArrayRef<Type *> PointerElementTypes,
Instruction *Pos, StringRef InstName);
typedef std::pair<std::vector<Value *>::iterator,
std::vector<Value *>::iterator>
ValueVecRange;
/// Add a vector at \param InsPos.
Value *addVector(Instruction *InsPos, ValueVecRange Range);
/// Replace scalar values with a vector created at \param InsPos.
void makeVector(Instruction *InsPos, std::vector<Value *> &Ops,
ValueVecRange Range);
/// Get size_t type.
IntegerType *getSizetType(Module *M);
/// Get a 64 bit integer constant.
ConstantInt *getInt64(Module *M, int64_t Value);
/// Get a 32 bit integer constant.
ConstantInt *getInt32(Module *M, int Value);
/// Get a 32 bit unsigned integer constant.
ConstantInt *getUInt32(Module *M, unsigned Value);
/// Get 32 bit integer constant if the value fits in 32 bits,
/// return 64 bit integer constant otherwise
ConstantInt *getInt(Module *M, int64_t Value);
/// Get 32 bit unsigned integer constant if the value fits in 32 bits,
/// return 64 bit unsigned integer constant otherwise
ConstantInt *getUInt(Module *M, uint64_t Value);
/// Get a 16 bit unsigned integer constant.
ConstantInt *getUInt16(Module *M, unsigned short Value);
// Get a 32 bit floating point constant.
Constant *getFloat32(Module *M, float Value);
/// Get a 32 bit integer constant vector.
std::vector<Value *> getInt32(Module *M, const std::vector<int> &Value);
/// Get a size_t type constant.
ConstantInt *getSizet(Module *M, uint64_t Value);
/// Get metadata operand as int.
int64_t getMDOperandAsInt(MDNode *N, unsigned I);
/// Get metadata operand as string.
StringRef getMDOperandAsString(MDNode *N, unsigned I);
/// Get metadata operand as another metadata node
MDNode *getMDOperandAsMDNode(MDNode *N, unsigned I);
/// Get metadata operand as type.
Type *getMDOperandAsType(MDNode *N, unsigned I);
/// Get a named metadata as a set of string.
/// Assume the named metadata has one or more operands each of which might
/// contain set of strings. For instance:
/// !opencl.used.optional.core.features = !{!0}
/// !0 = !{!"cl_doubles", !"cl_images"}
/// or if we linked two modules we may have
/// !opencl.used.optional.core.features = !{!0, !1}
/// !0 = !{!"cl_doubles"}
/// !1 = !{!"cl_images"}
std::set<std::string> getNamedMDAsStringSet(Module *M,
const std::string &MDName);
/// Get SPIR-V language by SPIR-V metadata spirv.Source
std::tuple<unsigned, unsigned, std::string> getSPIRVSource(Module *M);
/// Get postfix _R{ReturnType} for return type
/// The returned postfix does not includ "_" at the beginning
std::string getPostfixForReturnType(CallInst *CI, bool IsSigned = false);
std::string getPostfixForReturnType(const Type *PRetTy, bool IsSigned = false,
Type *PointerElementType = nullptr);
Constant *getScalarOrVectorConstantInt(Type *T, uint64_t V,
bool IsSigned = false);
/// Get a constant int or a constant int array.
/// \param T is the type of the constant. It should be an integer type or
// an integer pointer type.
/// \param Len is the length of the array.
/// \param V is the value to fill the array.
Value *getScalarOrArrayConstantInt(BasicBlock::iterator P, Type *T,
unsigned Len, uint64_t V,
bool IsSigned = false);
/// Get the array from GEP.
/// \param V is a GEP whose pointer operand is a pointer to an array of size
/// \param Size.
Value *getScalarOrArray(Value *V, unsigned Size, BasicBlock::iterator Pos);
void dumpUsers(Value *V, StringRef Prompt = "");
/// Get SPIR-V type name as spirv.BaseTyName.Postfixes.
std::string getSPIRVTypeName(StringRef BaseTyName, StringRef Postfixes = "");
/// Checks if given type name is either ConstantSampler or ConsantPipeStorage.
bool isSPIRVConstantName(StringRef TyName);
/// Get LLVM type for sampled type of SPIR-V image type by postfix.
Type *getLLVMTypeForSPIRVImageSampledTypePostfix(StringRef Postfix,
LLVMContext &Ctx);
/// Convert an LLVM type to a string postfix name.
std::string convertTypeToPostfix(Type *T);
/// Return the unqualified and unsuffixed base name of an image type.
/// E.g. opencl.image2d_ro_t.3 -> image2d_t
std::string getImageBaseTypeName(StringRef Name);
/// Extract the image type descriptor from the given image type.
SPIRVTypeImageDescriptor getImageDescriptor(Type *Ty);
/// Return the index of image operands given an image op.
size_t getImageOperandsIndex(Op OpCode);
/// Check if access qualifier is encoded in the type name.
bool hasAccessQualifiedName(StringRef TyName);
/// Get access qualifier from the type name.
SPIRVAccessQualifierKind getAccessQualifier(StringRef TyName);
/// Get access qualifier from the type name.
StringRef getAccessQualifierPostfix(SPIRVAccessQualifierKind Access);
bool eraseUselessFunctions(Module *M);
/// Erase a function if it is declaration, has internal linkage and has no use.
bool eraseIfNoUse(Function *F);
// Check if a mangled type name is unsigned
bool isMangledTypeUnsigned(char Mangled);
// Check if a mangled type name is signed
bool isMangledTypeSigned(char Mangled);
// Check if a mangled type name is floating point (except half)
bool isMangledTypeFP(char Mangled);
// Check if a mangled type name is half
bool isMangledTypeHalf(std::string Mangled);
// Check if \param I is valid vector size: 2, 3, 4, 8, 16.
bool isValidVectorSize(unsigned I);
enum class ParamType { FLOAT = 0, SIGNED = 1, UNSIGNED = 2, UNKNOWN = 3 };
ParamType lastFuncParamType(StringRef MangledName);
// Check if the last function parameter is signed
bool isLastFuncParamSigned(StringRef MangledName);
// Check if a mangled function name contains unsigned atomic type
bool containsUnsignedAtomicType(StringRef Name);
/// Mangle builtin function name.
/// \return \param UniqName if \param BtnInfo is null pointer, otherwise
/// return IA64 mangled name.
std::string mangleBuiltin(StringRef UniqName, ArrayRef<Type *> ArgTypes,
BuiltinFuncMangleInfo *BtnInfo,
const SPIRV::AddrSpaceMap *Map = nullptr);
/// Extract the true pointer types, expressed as a TypedPointerType, of
/// arguments from a mangled function name. If the corresponding type is not a
/// pointer type, its value will be the argument's actual type instead. Returns
/// true if the function name was successfully demangled.
bool getParameterTypes(
Function *F, SmallVectorImpl<Type *> &ArgTys,
std::function<std::string(StringRef)> StructNameMapFn = nullptr);
inline bool getParameterTypes(CallInst *CI, SmallVectorImpl<Type *> &ArgTys) {
return getParameterTypes(CI->getCalledFunction(), ArgTys);
}
enum class ParamSignedness { Signed = 0, Unsigned, Unknown };
/// Extract signedness of return type and parameter types from a mangled
/// function name.
bool getRetParamSignedness(Function *F, ParamSignedness &RetSignedness,
SmallVectorImpl<ParamSignedness> &ArgSignedness);
/// Mangle a function from OpenCL extended instruction set in SPIR-V friendly IR
/// manner
std::string
getSPIRVFriendlyIRFunctionName(OCLExtOpKind ExtOpId, ArrayRef<Type *> ArgTys,
Type *RetTy = nullptr,
const SPIRV::AddrSpaceMap *Map = nullptr);
/// Mangle a function in SPIR-V friendly IR manner
/// \param UniqName full unmangled name of the SPIR-V built-in function that
/// contains possible postfixes that depend not on opcode but on decorations or
/// return type, for example __spirv_UConvert_Rint_sat.
/// \param OC opcode of corresponding built-in instruction. Used to gather info
/// for unsigned/constant arguments.
/// \param Types of arguments of SPIR-V built-in function
/// \param Ops Operands of SPIRVInstruction
/// \return IA64 mangled name.
std::string getSPIRVFriendlyIRFunctionName(
const std::string &UniqName, spv::Op OC, ArrayRef<Type *> ArgTys,
ArrayRef<SPIRVValue *> Ops, const SPIRV::AddrSpaceMap *Map = nullptr);
/// Get i8* with the same address space.
PointerType *getInt8PtrTy(PointerType *T);
/// Cast a value to a i8* by inserting a cast instruction.
Value *castToInt8Ptr(Value *V, BasicBlock::iterator Pos);
template <> inline void SPIRVMap<std::string, Op, SPIRVOpaqueType>::init() {
#define _SPIRV_OP(x) add(#x, OpType##x);
_SPIRV_OP(DeviceEvent)
_SPIRV_OP(Event)
_SPIRV_OP(Image)
_SPIRV_OP(Pipe)
_SPIRV_OP(Queue)
_SPIRV_OP(ReserveId)
_SPIRV_OP(Sampler)
_SPIRV_OP(SampledImage)
_SPIRV_OP(PipeStorage)
// SPV_INTEL_device_side_avc_motion_estimation types
_SPIRV_OP(AvcMcePayloadINTEL)
_SPIRV_OP(AvcImePayloadINTEL)
_SPIRV_OP(AvcRefPayloadINTEL)
_SPIRV_OP(AvcSicPayloadINTEL)
_SPIRV_OP(AvcMceResultINTEL)
_SPIRV_OP(AvcImeResultINTEL)
_SPIRV_OP(AvcImeResultSingleReferenceStreamoutINTEL)
_SPIRV_OP(AvcImeResultDualReferenceStreamoutINTEL)
_SPIRV_OP(AvcImeSingleReferenceStreaminINTEL)
_SPIRV_OP(AvcImeDualReferenceStreaminINTEL)
_SPIRV_OP(AvcRefResultINTEL)
_SPIRV_OP(AvcSicResultINTEL)
_SPIRV_OP(VmeImageINTEL)
_SPIRV_OP(BufferSurfaceINTEL)
_SPIRV_OP(CooperativeMatrixKHR)
#undef _SPIRV_OP
add("TaskSequenceINTEL", internal::OpTypeTaskSequenceINTEL);
}
// Check if the module contains llvm.loop.* metadata
bool hasLoopMetadata(const Module *M);
// Check if CI is a call to instruction from OpenCL Extended Instruction Set.
// If so, return it's extended opcode in ExtOp.
bool isSPIRVOCLExtInst(const CallInst *CI, OCLExtOpKind *ExtOp);
/// Returns true if a function name corresponds to an OpenCL builtin that is not
/// expected to have name mangling.
bool isNonMangledOCLBuiltin(StringRef Name);
// check LLVM Intrinsics type(s) for validity
bool checkTypeForSPIRVExtendedInstLowering(IntrinsicInst *II, SPIRVModule *BM);
/// Decode SPIR-V type name in the format spirv.{TypeName}._{Postfixes}
/// where Postfixes are strings separated by underscores.
/// \return TypeName.
/// \param Strs contains the integers decoded from postfixes.
std::string decodeSPIRVTypeName(StringRef Name,
SmallVectorImpl<std::string> &Strs);
// Copy attributes from function to call site.
CallInst *setAttrByCalledFunc(CallInst *Call);
bool isSPIRVBuiltinVariable(GlobalVariable *GV, SPIRVBuiltinVariableKind *Kind);
// Transform builtin variable from GlobalVariable to builtin call.
// e.g.
// - GlobalInvocationId[x] -> _Z33__spirv_BuiltInGlobalInvocationIdi(x)
// - WorkDim -> _Z22__spirv_BuiltInWorkDimv()
bool lowerBuiltinVariableToCall(GlobalVariable *GV,
SPIRVBuiltinVariableKind Kind);
// Transform all builtin variables into calls
bool lowerBuiltinVariablesToCalls(Module *M);
// Transform all builtin calls into variables
bool lowerBuiltinCallsToVariables(Module *M);
// Transform all builtins into variables or calls
// depending on user specification
bool lowerBuiltins(SPIRVModule *BM, Module *M);
/// \brief Post-process OpenCL or SPIRV builtin function returning struct type.
///
/// Some builtin functions are translated to SPIR-V instructions with
/// struct type result, e.g. NDRange creation functions. Such functions
/// need to be post-processed to return the struct through sret argument.
bool postProcessBuiltinReturningStruct(Function *F);
/// \brief Post-process OpenCL or SPIRV builtin function having array argument.
///
/// These functions are translated to functions with array type argument
/// first, then post-processed to have pointer arguments.
bool postProcessBuiltinWithArrayArguments(Function *F, StringRef DemangledName);
bool postProcessBuiltinsReturningStruct(Module *M, bool IsCpp = false);
bool postProcessBuiltinsWithArrayArguments(Module *M, bool IsCpp = false);
/// \param MangledName LLVM function name.
/// \param DemangledName demangled name of the input function if it is the
/// translator's internal built-in function.
/// \returns true if MangledName is the name of the translator's internal
/// built-in function, false for other functions.
/// Used for 'mini'-floats conversion functions
bool isInternalSPIRVBuiltin(StringRef MangledName, StringRef &DemangledName);
// Wrapper around SPIR-V 1.6.4 FP Encoding to be used in the conversion
// descriptor
enum FPEncodingWrap {
Integer = FPEncoding::FPEncodingMax - 1,
IEEE754 = FPEncoding::FPEncodingMax,
BF16 = FPEncoding::FPEncodingBFloat16KHR,
E4M3 = FPEncoding::FPEncodingFloat8E4M3EXT,
E5M2 = FPEncoding::FPEncodingFloat8E5M2EXT,
E2M1 = internal::FPEncodingFloat4E2M1INTEL,
};
// Structure describing non-trivial conversions (FP8 and int4)
struct FPConversionDesc {
FPEncodingWrap SrcEncoding;
FPEncodingWrap DstEncoding;
SPIRVWord ConvOpCode;
// To use as a key in std::map
bool operator==(const FPConversionDesc &Other) const {
return SrcEncoding == Other.SrcEncoding &&
DstEncoding == Other.DstEncoding && ConvOpCode == Other.ConvOpCode;
}
bool operator<(const FPConversionDesc &Other) const {
if (ConvOpCode != Other.ConvOpCode)
return ConvOpCode < Other.ConvOpCode;
if (SrcEncoding != Other.SrcEncoding)
return SrcEncoding < Other.SrcEncoding;
return DstEncoding < Other.DstEncoding;
}
};
// Maps internal builtin name to conversion descriptor
typedef SPIRVMap<llvm::StringRef, FPConversionDesc> FPConvertToEncodingMap;
// clang-format off
template <> inline void FPConvertToEncodingMap::init() {
// 4-bit conversions
add("ConvertE2M1ToE4M3INTEL",
{FPEncodingWrap::E2M1, FPEncodingWrap::E4M3, OpFConvert});
add("ConvertE2M1ToE5M2INTEL",
{FPEncodingWrap::E2M1, FPEncodingWrap::E5M2, OpFConvert});
add("ConvertE2M1ToFP16INTEL",
{FPEncodingWrap::E2M1, FPEncodingWrap::IEEE754, OpFConvert});
add("ConvertE2M1ToBF16INTEL",
{FPEncodingWrap::E2M1, FPEncodingWrap::BF16, OpFConvert});
add("ConvertInt4ToE4M3INTEL",
{FPEncodingWrap::Integer, FPEncodingWrap::E4M3, OpConvertSToF});
add("ConvertInt4ToE5M2INTEL",
{FPEncodingWrap::Integer, FPEncodingWrap::E5M2, OpConvertSToF});
add("ConvertInt4ToFP16INTEL",
{FPEncodingWrap::Integer, FPEncodingWrap::IEEE754, OpConvertSToF});
add("ConvertInt4ToBF16INTEL",
{FPEncodingWrap::Integer, FPEncodingWrap::BF16, OpConvertSToF});
add("ConvertInt4ToInt8INTEL",
{FPEncodingWrap::Integer, FPEncodingWrap::Integer, OpSConvert});
add("ConvertFP16ToE2M1INTEL",
{FPEncodingWrap::IEEE754, FPEncodingWrap::E2M1, OpFConvert});
add("ConvertBF16ToE2M1INTEL",
{FPEncodingWrap::BF16, FPEncodingWrap::E2M1, OpFConvert});
add("ConvertFP16ToInt4INTEL",
{FPEncodingWrap::IEEE754, FPEncodingWrap::Integer, OpConvertFToS});
add("ConvertBF16ToInt4INTEL",
{FPEncodingWrap::BF16, FPEncodingWrap::Integer, OpConvertFToS});
// 8-bit conversions
add("ConvertE4M3ToFP16EXT",
{FPEncodingWrap::E4M3, FPEncodingWrap::IEEE754, OpFConvert});
add("ConvertE5M2ToFP16EXT",
{FPEncodingWrap::E5M2, FPEncodingWrap::IEEE754, OpFConvert});
add("ConvertE4M3ToBF16EXT",
{FPEncodingWrap::E4M3, FPEncodingWrap::BF16, OpFConvert});
add("ConvertE5M2ToBF16EXT",
{FPEncodingWrap::E5M2, FPEncodingWrap::BF16, OpFConvert});
add("ConvertFP16ToE4M3EXT",
{FPEncodingWrap::IEEE754, FPEncodingWrap::E4M3, OpFConvert});
add("ConvertFP16ToE5M2EXT",
{FPEncodingWrap::IEEE754, FPEncodingWrap::E5M2, OpFConvert});
add("ConvertBF16ToE4M3EXT",
{FPEncodingWrap::BF16, FPEncodingWrap::E4M3, OpFConvert});
add("ConvertBF16ToE5M2EXT",
{FPEncodingWrap::BF16, FPEncodingWrap::E5M2, OpFConvert});
// SPV_INTEL_fp_conversions
add("ClampConvertFP16ToE2M1INTEL",
{FPEncodingWrap::IEEE754, FPEncodingWrap::E2M1,
internal::OpClampConvertFToFINTEL});
add("ClampConvertBF16ToE2M1INTEL",
{FPEncodingWrap::BF16, FPEncodingWrap::E2M1,
internal::OpClampConvertFToFINTEL});
add("ClampConvertFP16ToE4M3INTEL",
{FPEncodingWrap::IEEE754, FPEncodingWrap::E4M3,
internal::OpClampConvertFToFINTEL});
add("ClampConvertBF16ToE4M3INTEL",
{FPEncodingWrap::BF16, FPEncodingWrap::E4M3,
internal::OpClampConvertFToFINTEL});
add("ClampConvertFP16ToE5M2INTEL",
{FPEncodingWrap::IEEE754, FPEncodingWrap::E5M2,
internal::OpClampConvertFToFINTEL});
add("ClampConvertBF16ToE5M2INTEL",
{FPEncodingWrap::BF16, FPEncodingWrap::E5M2,
internal::OpClampConvertFToFINTEL});
add("ClampConvertFP16ToInt4INTEL",
{FPEncodingWrap::IEEE754, FPEncodingWrap::Integer,
internal::OpClampConvertFToSINTEL});
add("ClampConvertBF16ToInt4INTEL",
{FPEncodingWrap::BF16, FPEncodingWrap::Integer,
internal::OpClampConvertFToSINTEL});
add("StochasticRoundFP16ToE5M2INTEL",
{FPEncodingWrap::IEEE754, FPEncodingWrap::E5M2,
internal::OpStochasticRoundFToFINTEL});
add("StochasticRoundFP16ToE4M3INTEL",
{FPEncodingWrap::IEEE754, FPEncodingWrap::E4M3,
internal::OpStochasticRoundFToFINTEL});
add("StochasticRoundBF16ToE5M2INTEL",
{FPEncodingWrap::BF16, FPEncodingWrap::E5M2,
internal::OpStochasticRoundFToFINTEL});
add("StochasticRoundBF16ToE4M3INTEL",
{FPEncodingWrap::BF16, FPEncodingWrap::E4M3,
internal::OpStochasticRoundFToFINTEL});
add("StochasticRoundFP16ToE2M1INTEL",
{FPEncodingWrap::IEEE754, FPEncodingWrap::E2M1,
internal::OpStochasticRoundFToFINTEL});
add("StochasticRoundBF16ToE2M1INTEL",
{FPEncodingWrap::BF16, FPEncodingWrap::E2M1,
internal::OpStochasticRoundFToFINTEL});
add("ClampStochasticRoundFP16ToInt4INTEL",
{FPEncodingWrap::IEEE754, FPEncodingWrap::Integer,
internal::OpClampStochasticRoundFToSINTEL});
add("ClampStochasticRoundBF16ToInt4INTEL",
{FPEncodingWrap::BF16, FPEncodingWrap::Integer,
internal::OpClampStochasticRoundFToSINTEL});
add("ClampStochasticRoundFP16ToE5M2INTEL",
{FPEncodingWrap::IEEE754, FPEncodingWrap::E5M2,
internal::OpClampStochasticRoundFToFINTEL});
add("ClampStochasticRoundFP16ToE4M3INTEL",
{FPEncodingWrap::IEEE754, FPEncodingWrap::E4M3,
internal::OpClampStochasticRoundFToFINTEL});
add("ClampStochasticRoundBF16ToE5M2INTEL",
{FPEncodingWrap::BF16, FPEncodingWrap::E5M2,
internal::OpClampStochasticRoundFToFINTEL});
add("ClampStochasticRoundBF16ToE4M3INTEL",
{FPEncodingWrap::BF16, FPEncodingWrap::E4M3,
internal::OpClampStochasticRoundFToFINTEL});
}
// clang-format on
} // namespace SPIRV
#endif // SPIRV_SPIRVINTERNAL_H