941 lines
34 KiB
C++
941 lines
34 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 LLVMSPIRVINTERNAL_HPP_
|
|
#define LLVMSPIRVINTERNAL_HPP_
|
|
|
|
#include "libSPIRV/SPIRVUtil.h"
|
|
#include "libSPIRV/SPIRVEnum.h"
|
|
#include "libSPIRV/SPIRVNameMapEnum.h"
|
|
#include "libSPIRV/SPIRVError.h"
|
|
#include "libSPIRV/SPIRVType.h"
|
|
#include "NameMangleAPI.h"
|
|
|
|
#include "llvm/IR/Attributes.h"
|
|
#include "llvm/IR/Constants.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/Support/SPIRV.h"
|
|
|
|
#include <utility>
|
|
#include <functional>
|
|
|
|
using namespace SPIRV;
|
|
using 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;
|
|
|
|
#define SPCV_TARGET_LLVM_IMAGE_TYPE_ENCODE_ACCESS_QUAL 0
|
|
// Workaround for SPIR 2 producer bug about kernel function calling convention.
|
|
// This workaround checks metadata to determine if a function is kernel.
|
|
#define SPCV_RELAX_KERNEL_CALLING_CONV 1
|
|
|
|
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"
|
|
|
|
namespace kOCLTypeQualifierName {
|
|
const static char *Const = "const";
|
|
const static char *Volatile = "volatile";
|
|
const static char *Restrict = "restrict";
|
|
const static char *Pipe = "pipe";
|
|
}
|
|
|
|
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)
|
|
/*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"
|
|
|
|
enum SPIRAddressSpace {
|
|
SPIRAS_Private,
|
|
SPIRAS_Global,
|
|
SPIRAS_Constant,
|
|
SPIRAS_Local,
|
|
SPIRAS_Generic,
|
|
SPIRAS_Count,
|
|
};
|
|
|
|
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");
|
|
}
|
|
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);
|
|
}
|
|
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::NoCapture, FunctionParameterAttributeNoCapture);
|
|
}
|
|
typedef SPIRVMap<Attribute::AttrKind, SPIRVFuncParamAttrKind>
|
|
SPIRSPIRVFuncParamAttrMap;
|
|
|
|
template<> inline void
|
|
SPIRVMap<Attribute::AttrKind, SPIRVFunctionControlMaskKind>::init() {
|
|
add(Attribute::ReadNone, FunctionControlPureMask);
|
|
add(Attribute::ReadOnly, FunctionControlConstMask);
|
|
add(Attribute::AlwaysInline, FunctionControlInlineMask);
|
|
add(Attribute::NoInline, FunctionControlDontInlineMask);
|
|
}
|
|
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_KERNELS "opencl.kernels"
|
|
#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 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 kSPIRVImageSampledTypeName {
|
|
const static char Float[] = "float";
|
|
const static char Half[] = "half";
|
|
const static char Int[] = "int";
|
|
const static char UInt[] = "uint";
|
|
const static char Void[] = "void";
|
|
}
|
|
|
|
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";
|
|
}
|
|
|
|
namespace kSPR2TypeName {
|
|
const static char Delimiter = '.';
|
|
const static char OCLPrefix[] = "opencl.";
|
|
const static char ImagePrefix[] = "opencl.image";
|
|
const static char Pipe[] = "opencl.pipe_t";
|
|
const static char Sampler[] = "opencl.sampler_t";
|
|
const static char Event[] = "opencl.event_t";
|
|
}
|
|
|
|
namespace kAccessQualName {
|
|
const static char ReadOnly[] = "read_only";
|
|
const static char WriteOnly[] = "write_only";
|
|
const static char ReadWrite[] = "read_write";
|
|
}
|
|
|
|
namespace kMangledName {
|
|
const static char Sampler[] = "11ocl_sampler";
|
|
const static char AtomicPrefixIncoming[] = "U7_Atomic";
|
|
const static char AtomicPrefixInternal[] = "atomic_";
|
|
}
|
|
|
|
namespace kSPIRVName {
|
|
const static char GroupPrefix[] = "group_";
|
|
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";
|
|
}
|
|
|
|
namespace kSPIRVPostfix {
|
|
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 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 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 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";
|
|
}
|
|
|
|
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;
|
|
BuiltinArgTypeMangleInfo():IsSigned(true), IsVoidPtr(false), IsEnum(false),
|
|
IsSampler(false), IsAtomic(false), IsLocalArgBlock(false),
|
|
Enum(SPIR::PRIMITIVE_NONE), Attr(0)
|
|
{}
|
|
};
|
|
|
|
/// Information for mangling builtin function.
|
|
class BuiltinFuncMangleInfo {
|
|
public:
|
|
/// Translate builtin function name and set
|
|
/// argument attributes and unsigned args.
|
|
BuiltinFuncMangleInfo(const std::string &UniqName = "") : LocalArgBlockIdx(-1),
|
|
VarArgIdx(-1) {
|
|
if (!UniqName.empty())
|
|
init(UniqName);
|
|
}
|
|
virtual ~BuiltinFuncMangleInfo(){}
|
|
const std::string &getUnmangledName() const { return UnmangledName;}
|
|
void addUnsignedArg(int Ndx) { UnsignedArgs.insert(Ndx);}
|
|
void addVoidPtrArg(int Ndx) { VoidPtrArgs.insert(Ndx);}
|
|
void addSamplerArg(int Ndx) { SamplerArgs.insert(Ndx);}
|
|
void addAtomicArg(int Ndx) { AtomicArgs.insert(Ndx);}
|
|
void setLocalArgBlock(int Ndx) {
|
|
assert(0 <= Ndx && "it is not allowed to set less than zero index");
|
|
LocalArgBlockIdx = Ndx;
|
|
}
|
|
void setEnumArg(int Ndx, SPIR::TypePrimitiveEnum Enum) {
|
|
EnumArgs[Ndx] = Enum;}
|
|
void setArgAttr(int Ndx, unsigned Attr) {
|
|
Attrs[Ndx] = Attr;}
|
|
void setVarArg(int Ndx) {
|
|
assert(0 <= Ndx && "it is not allowed to set less than zero index");
|
|
VarArgIdx = Ndx;
|
|
}
|
|
bool isArgUnsigned(int Ndx) {
|
|
return UnsignedArgs.count(-1) || UnsignedArgs.count(Ndx);}
|
|
bool isArgVoidPtr(int Ndx) {
|
|
return VoidPtrArgs.count(-1) || VoidPtrArgs.count(Ndx);}
|
|
bool isArgSampler(int Ndx) {
|
|
return SamplerArgs.count(Ndx);}
|
|
bool isArgAtomic(int Ndx) {
|
|
return AtomicArgs.count(Ndx);}
|
|
bool isLocalArgBlock(int Ndx) {
|
|
return LocalArgBlockIdx == Ndx;}
|
|
bool isArgEnum(int Ndx, SPIR::TypePrimitiveEnum *Enum = nullptr) {
|
|
auto Loc = EnumArgs.find(Ndx);
|
|
if (Loc == EnumArgs.end())
|
|
Loc = EnumArgs.find(-1);
|
|
if (Loc == EnumArgs.end())
|
|
return false;
|
|
if (Enum)
|
|
*Enum = Loc->second;
|
|
return true;
|
|
}
|
|
unsigned getArgAttr(int Ndx) {
|
|
auto Loc = Attrs.find(Ndx);
|
|
if (Loc == Attrs.end())
|
|
Loc = Attrs.find(-1);
|
|
if (Loc == Attrs.end())
|
|
return 0;
|
|
return Loc->second;
|
|
}
|
|
// 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(int Ndx) {
|
|
BuiltinArgTypeMangleInfo Info;
|
|
Info.IsSigned = !isArgUnsigned(Ndx);
|
|
Info.IsVoidPtr = isArgVoidPtr(Ndx);
|
|
Info.IsEnum = isArgEnum(Ndx, &Info.Enum);
|
|
Info.IsSampler = isArgSampler(Ndx);
|
|
Info.IsAtomic = isArgAtomic(Ndx);
|
|
Info.IsLocalArgBlock = isLocalArgBlock(Ndx);
|
|
Info.Attr = getArgAttr(Ndx);
|
|
return Info;
|
|
}
|
|
virtual void init(const std::string &UniqUnmangledName){
|
|
UnmangledName = UniqUnmangledName;
|
|
}
|
|
protected:
|
|
std::string UnmangledName;
|
|
std::set<int> UnsignedArgs; // unsigned arguments, or -1 if all are unsigned
|
|
std::set<int> VoidPtrArgs; // void pointer arguments, or -1 if all are void
|
|
// pointer
|
|
std::set<int> SamplerArgs; // sampler arguments
|
|
std::set<int> AtomicArgs; // atomic arguments
|
|
std::map<int, SPIR::TypePrimitiveEnum> EnumArgs; // enum arguments
|
|
std::map<int, unsigned> Attrs; // argument attributes
|
|
int LocalArgBlockIdx; // index of a block with local arguments, idx < 0 if none
|
|
int VarArgIdx; // index of ellipsis argument, idx < 0 if none
|
|
};
|
|
|
|
/// \returns a vector of types for a collection of values.
|
|
template<class T>
|
|
std::vector<Type *>
|
|
getTypes(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.
|
|
inline size_t findFirstPtr(const std::vector<Value *> &Args) {
|
|
auto PtArg = std::find_if(Args.begin(), Args.end(), [](Value *V){
|
|
return V->getType()->isPointerTy();
|
|
});
|
|
return PtArg - Args.begin();
|
|
}
|
|
|
|
void removeFnAttr(LLVMContext *Context, CallInst *Call,
|
|
Attribute::AttrKind Attr);
|
|
void addFnAttr(LLVMContext *Context, CallInst *Call,
|
|
Attribute::AttrKind Attr);
|
|
void saveLLVMModule(Module *M, const std::string &OutputFile);
|
|
std::string mapSPIRVTypeToOCLType(SPIRVType* Ty, bool Signed);
|
|
std::string mapLLVMTypeToOCLType(const Type* Ty, bool Signed);
|
|
SPIRVDecorate *mapPostfixToDecorate(StringRef Postfix, SPIRVEntry *Target);
|
|
|
|
/// 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);
|
|
|
|
PointerType *getOrCreateOpaquePtrType(Module *M, const std::string &Name,
|
|
unsigned AddrSpace = SPIRAS_Global);
|
|
PointerType* getSamplerType(Module *M);
|
|
PointerType* getPipeStorageType(Module *M);
|
|
void getFunctionTypeParameterTypes(llvm::FunctionType* FT,
|
|
std::vector<Type*>& ArgTys);
|
|
Function *getOrCreateFunction(Module *M, Type *RetTy,
|
|
ArrayRef<Type *> ArgTypes, StringRef Name,
|
|
BuiltinFuncMangleInfo *Mangle = nullptr,
|
|
AttributeSet *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);
|
|
|
|
/// Get constant function call argument as a Decoration enum.
|
|
/// \param I argument index.
|
|
Decoration getArgAsDecoration(CallInst *CI, unsigned I);
|
|
|
|
bool isPointerToOpaqueStructType(llvm::Type* Ty);
|
|
bool isPointerToOpaqueStructType(llvm::Type* Ty, const std::string &Name);
|
|
|
|
/// 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
|
|
isSPIRVType(llvm::Type* Ty, StringRef BaseTyName, StringRef *Postfix = 0);
|
|
|
|
/// Decorate a function name as __spirv_{Name}_
|
|
std::string decorateSPIRVFunction(const std::string &S);
|
|
|
|
/// Remove prefix/postfix from __spirv_{Name}_
|
|
std::string undecorateSPIRVFunction(const std::string &S);
|
|
|
|
/// Check if a function has decorated name as __spirv_{Name}_
|
|
/// and get the original name.
|
|
bool isDecoratedSPIRVFunc(const Function *F, std::string *UndecName = nullptr);
|
|
|
|
/// 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);
|
|
|
|
/// 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(const std::string& 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 demanged 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(const StringRef &Name, std::string *DemangledName = nullptr,
|
|
bool isCPP = false);
|
|
|
|
/// Check if a function type is void(void).
|
|
bool isVoidFuncTy(FunctionType *FT);
|
|
|
|
/// \returns true if \p T is a function pointer type.
|
|
bool isFunctionPointerType(Type *T);
|
|
|
|
/// \returns true if function \p F has function pointer type argument.
|
|
/// \param AI points to the function pointer type argument if returns true.
|
|
bool hasFunctionPointerArg(Function *F, Function::arg_iterator& AI);
|
|
|
|
/// \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, AttributeSet *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, AttributeSet *Attrs = nullptr,
|
|
bool takeName = false);
|
|
|
|
/// Mutate call instruction to call SPIR-V builtin function.
|
|
CallInst *
|
|
mutateCallInstSPIRV(Module *M, CallInst *CI,
|
|
std::function<std::string (CallInst *, std::vector<Value *> &)>ArgMutate,
|
|
AttributeSet *Attrs = nullptr);
|
|
|
|
/// Mutate call instruction to call SPIR-V builtin function.
|
|
Instruction *
|
|
mutateCallInstSPIRV(Module *M, CallInst *CI,
|
|
std::function<std::string (CallInst *, std::vector<Value *> &,
|
|
Type *&RetTy)> ArgMutate,
|
|
std::function<Instruction *(CallInst *)> RetMutate,
|
|
AttributeSet *Attrs = nullptr);
|
|
|
|
/// 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, AttributeSet *Attrs = nullptr,
|
|
bool TakeName = true);
|
|
|
|
/// Add a call instruction at \p Pos.
|
|
CallInst *addCallInst(Module *M, StringRef FuncName, Type *RetTy,
|
|
ArrayRef<Value *> Args, AttributeSet *Attrs, Instruction *Pos,
|
|
BuiltinFuncMangleInfo *Mangle = nullptr,
|
|
StringRef InstName = SPIR_TEMP_NAME_PREFIX_CALL,
|
|
bool TakeFuncName = true);
|
|
|
|
/// Add a call instruction for SPIR-V builtin function.
|
|
CallInst *
|
|
addCallInstSPIRV(Module *M, StringRef FuncName, Type *RetTy,
|
|
ArrayRef<Value *> Args,
|
|
AttributeSet *Attrs, Instruction *Pos, StringRef InstName);
|
|
|
|
/// Add a call of spir_block_bind function.
|
|
CallInst *
|
|
addBlockBind(Module *M, Function *InvokeFunc, Value *BlkCtx, Value *CtxLen,
|
|
Value *CtxAlign, Instruction *InsPos,
|
|
StringRef InstName = SPIR_TEMP_NAME_PREFIX_BLOCK);
|
|
|
|
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);
|
|
|
|
/// Expand a vector type value in \param Ops at index \param VecPos.
|
|
/// Generate extract element instructions at \param InsPos and replace
|
|
/// the vector type value with scalar type values.
|
|
/// If the value to be expanded is not vector type, do nothing.
|
|
void
|
|
expandVector(Instruction *InsPos, std::vector<Value *> &Ops, size_t VecPos);
|
|
|
|
/// Get size_t type.
|
|
IntegerType *getSizetType(Module *M);
|
|
|
|
/// Get void(void) function type.
|
|
Type *getVoidFuncType(Module *M);
|
|
|
|
/// Get void(void) function pointer type.
|
|
Type *getVoidFuncPtrType(Module *M, unsigned AddrSpace = 0);
|
|
|
|
/// 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 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.
|
|
int getMDOperandAsInt(MDNode* N, unsigned I);
|
|
|
|
/// Get metadata operand as string.
|
|
std::string getMDOperandAsString(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);
|
|
|
|
/// Map an unsigned integer constant by applying a function.
|
|
ConstantInt *mapUInt(Module *M, ConstantInt *I,
|
|
std::function<unsigned(unsigned)> F);
|
|
|
|
/// Map a signed integer constant by applying a function.
|
|
ConstantInt *mapSInt(Module *M, ConstantInt *I,
|
|
std::function<int(int)> F);
|
|
|
|
/// Get postfix for given decoration.
|
|
/// The returned postfix does not include "_" at the beginning.
|
|
std::string getPostfix(Decoration Dec, unsigned Value = 0);
|
|
|
|
/// 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);
|
|
|
|
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(Instruction *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, Instruction *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 SPIR-V type by changing the type name from spirv.OldName.Postfixes
|
|
/// to spirv.NewName.Postfixes.
|
|
Type *
|
|
getSPIRVTypeByChangeBaseTypeName(Module *M, Type *T, StringRef OldName,
|
|
StringRef NewName);
|
|
|
|
/// Get the postfixes of SPIR-V image type name as in spirv.Image.postfixes.
|
|
std::string
|
|
getSPIRVImageTypePostfixes(StringRef SampledType,
|
|
SPIRVTypeImageDescriptor Desc,
|
|
SPIRVAccessQualifierKind Acc);
|
|
|
|
/// Get the sampled type name used in postfix of image type in SPIR-V
|
|
/// friendly LLVM IR.
|
|
std::string
|
|
getSPIRVImageSampledTypeName(SPIRVType *Ty);
|
|
|
|
/// Translates OpenCL image type names to SPIR-V.
|
|
/// E.g. %opencl.image1d_rw_t -> %spirv.Image._void_0_0_0_0_0_0_2
|
|
Type *getSPIRVImageTypeFromOCL(Module *M, Type *T);
|
|
|
|
/// Get LLVM type for sampled type of SPIR-V image type by postfix.
|
|
Type*
|
|
getLLVMTypeForSPIRVImageSampledTypePostfix(StringRef Postfix,
|
|
LLVMContext &Ctx);
|
|
|
|
/// Map OpenCL opaque type name to SPIR-V type name.
|
|
std::string
|
|
mapOCLTypeNameToSPIRV(StringRef Name, StringRef Acc = "");
|
|
|
|
/// Check if access qualifier is encoded in the type name.
|
|
bool hasAccessQualifiedName(StringRef TyName);
|
|
|
|
/// Get access qualifier from the type name.
|
|
StringRef getAccessQualifier(StringRef TyName);
|
|
|
|
bool
|
|
eraseUselessFunctions(Module *M);
|
|
|
|
/// Erase a function if it is declaration, has internal linkage and has no use.
|
|
bool
|
|
eraseIfNoUse(Function *F);
|
|
|
|
void
|
|
eraseIfNoUse(Value *V);
|
|
|
|
// 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(const std::string& MangledName);
|
|
|
|
// Check if the last function parameter is signed
|
|
bool
|
|
isLastFuncParamSigned(const std::string& 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(const std::string &UniqName,
|
|
ArrayRef<Type*> ArgTypes, BuiltinFuncMangleInfo* BtnInfo);
|
|
|
|
/// Remove cast from a value.
|
|
Value *
|
|
removeCast(Value *V);
|
|
|
|
/// Cast a function to a void(void) funtion pointer.
|
|
Constant *
|
|
castToVoidFuncPtr(Function *F);
|
|
|
|
/// 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, Instruction *Pos);
|
|
|
|
template<> inline void
|
|
SPIRVMap<std::string, Op, SPIRVOpaqueType>::init() {
|
|
add(kSPIRVTypeName::DeviceEvent, OpTypeDeviceEvent);
|
|
add(kSPIRVTypeName::Event, OpTypeEvent);
|
|
add(kSPIRVTypeName::Image, OpTypeImage);
|
|
add(kSPIRVTypeName::Pipe, OpTypePipe);
|
|
add(kSPIRVTypeName::Queue, OpTypeQueue);
|
|
add(kSPIRVTypeName::ReserveId, OpTypeReserveId);
|
|
add(kSPIRVTypeName::Sampler, OpTypeSampler);
|
|
add(kSPIRVTypeName::SampledImg, OpTypeSampledImage);
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|