This PR contains a series of fixes which are to improve type inference and instruction selection. Namely, it includes: * fix OpSelect to support operands of a pointer type, according to the SPIR-V specification (previously only integer/float/vectors of integer or float were supported) -- a new test case is added and existing test case is updated; * fix TableGen typo's in definition of register classes and introduce a new reg class that is a vector of pointers; * fix usage of a machine function context when there is a need to switch between different machine functions to infer/validate correct types; * add usage of TypedPointerType instead of PointerType so that later stages of type inference are able to distinguish pointer types by their element types, effectively supporting hierarchy of pointer/pointee types and avoiding more complicated recursive type matching on level of machine instructions in favor of direct pointer comparison using LLVM's `Type *` values; * extracting detailed information about operand types using known type rules for some llvm instructions (for instance, by deducing PHI's operand pointee types if PHI's results type was deducted on previous stages of type inference), and adding correspondent `Intrinsic::spv_assign_ptr_type` to keep type info along consequent passes, * ensure that OpConstantComposite reuses a constant when it's already created and available in the same machine function -- otherwise there is a crash while building a dependency graph, the corresponding test case is attached, * implement deduction of function's return type for opaque pointers, a new test case is attached, * make 'emit intrinsics' a module pass to resolve function return types over the module -- first types for all functions of the module must be calculated, and only after that it's feasible to deduct function return types on this earlier stage of translation.
161 lines
5.9 KiB
C++
161 lines
5.9 KiB
C++
//===--- SPIRVUtils.h ---- SPIR-V Utility Functions -------------*- C++ -*-===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file contains miscellaneous utility functions.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H
|
|
#define LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H
|
|
|
|
#include "MCTargetDesc/SPIRVBaseInfo.h"
|
|
#include "llvm/IR/IRBuilder.h"
|
|
#include "llvm/IR/TypedPointerType.h"
|
|
#include <string>
|
|
|
|
namespace llvm {
|
|
class MCInst;
|
|
class MachineFunction;
|
|
class MachineInstr;
|
|
class MachineInstrBuilder;
|
|
class MachineIRBuilder;
|
|
class MachineRegisterInfo;
|
|
class Register;
|
|
class StringRef;
|
|
class SPIRVInstrInfo;
|
|
class SPIRVSubtarget;
|
|
|
|
// Add the given string as a series of integer operand, inserting null
|
|
// terminators and padding to make sure the operands all have 32-bit
|
|
// little-endian words.
|
|
void addStringImm(const StringRef &Str, MCInst &Inst);
|
|
void addStringImm(const StringRef &Str, MachineInstrBuilder &MIB);
|
|
void addStringImm(const StringRef &Str, IRBuilder<> &B,
|
|
std::vector<Value *> &Args);
|
|
|
|
// Read the series of integer operands back as a null-terminated string using
|
|
// the reverse of the logic in addStringImm.
|
|
std::string getStringImm(const MachineInstr &MI, unsigned StartIndex);
|
|
|
|
// Add the given numerical immediate to MIB.
|
|
void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB);
|
|
|
|
// Add an OpName instruction for the given target register.
|
|
void buildOpName(Register Target, const StringRef &Name,
|
|
MachineIRBuilder &MIRBuilder);
|
|
|
|
// Add an OpDecorate instruction for the given Reg.
|
|
void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder,
|
|
SPIRV::Decoration::Decoration Dec,
|
|
const std::vector<uint32_t> &DecArgs,
|
|
StringRef StrImm = "");
|
|
void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII,
|
|
SPIRV::Decoration::Decoration Dec,
|
|
const std::vector<uint32_t> &DecArgs,
|
|
StringRef StrImm = "");
|
|
|
|
// Convert a SPIR-V storage class to the corresponding LLVM IR address space.
|
|
unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC);
|
|
|
|
// Convert an LLVM IR address space to a SPIR-V storage class.
|
|
SPIRV::StorageClass::StorageClass
|
|
addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI);
|
|
|
|
SPIRV::MemorySemantics::MemorySemantics
|
|
getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC);
|
|
|
|
SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord);
|
|
|
|
// Find def instruction for the given ConstReg, walking through
|
|
// spv_track_constant and ASSIGN_TYPE instructions. Updates ConstReg by def
|
|
// of OpConstant instruction.
|
|
MachineInstr *getDefInstrMaybeConstant(Register &ConstReg,
|
|
const MachineRegisterInfo *MRI);
|
|
|
|
// Get constant integer value of the given ConstReg.
|
|
uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI);
|
|
|
|
// Check if MI is a SPIR-V specific intrinsic call.
|
|
bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID);
|
|
|
|
// Get type of i-th operand of the metadata node.
|
|
Type *getMDOperandAsType(const MDNode *N, unsigned I);
|
|
|
|
// If OpenCL or SPIR-V builtin function name is recognized, return a demangled
|
|
// name, otherwise return an empty string.
|
|
std::string getOclOrSpirvBuiltinDemangledName(StringRef Name);
|
|
|
|
// Check if a string contains a builtin prefix.
|
|
bool hasBuiltinTypePrefix(StringRef Name);
|
|
|
|
// Check if given LLVM type is a special opaque builtin type.
|
|
bool isSpecialOpaqueType(const Type *Ty);
|
|
|
|
// Check if the function is an SPIR-V entry point
|
|
bool isEntryPoint(const Function &F);
|
|
|
|
// Parse basic scalar type name, substring TypeName, and return LLVM type.
|
|
Type *parseBasicTypeName(StringRef TypeName, LLVMContext &Ctx);
|
|
|
|
// True if this is an instance of TypedPointerType.
|
|
inline bool isTypedPointerTy(const Type *T) {
|
|
return T->getTypeID() == Type::TypedPointerTyID;
|
|
}
|
|
|
|
// True if this is an instance of PointerType.
|
|
inline bool isUntypedPointerTy(const Type *T) {
|
|
return T->getTypeID() == Type::PointerTyID;
|
|
}
|
|
|
|
// True if this is an instance of PointerType or TypedPointerType.
|
|
inline bool isPointerTy(const Type *T) {
|
|
return isUntypedPointerTy(T) || isTypedPointerTy(T);
|
|
}
|
|
|
|
// Get the address space of this pointer or pointer vector type for instances of
|
|
// PointerType or TypedPointerType.
|
|
inline unsigned getPointerAddressSpace(const Type *T) {
|
|
Type *SubT = T->getScalarType();
|
|
return SubT->getTypeID() == Type::PointerTyID
|
|
? cast<PointerType>(SubT)->getAddressSpace()
|
|
: cast<TypedPointerType>(SubT)->getAddressSpace();
|
|
}
|
|
|
|
// Return true if the Argument is decorated with a pointee type
|
|
inline bool hasPointeeTypeAttr(Argument *Arg) {
|
|
return Arg->hasByValAttr() || Arg->hasByRefAttr() || Arg->hasStructRetAttr();
|
|
}
|
|
|
|
// Return the pointee type of the argument or nullptr otherwise
|
|
inline Type *getPointeeTypeByAttr(Argument *Arg) {
|
|
if (Arg->hasByValAttr())
|
|
return Arg->getParamByValType();
|
|
if (Arg->hasStructRetAttr())
|
|
return Arg->getParamStructRetType();
|
|
if (Arg->hasByRefAttr())
|
|
return Arg->getParamByRefType();
|
|
return nullptr;
|
|
}
|
|
|
|
inline Type *reconstructFunctionType(Function *F) {
|
|
SmallVector<Type *> ArgTys;
|
|
for (unsigned i = 0; i < F->arg_size(); ++i)
|
|
ArgTys.push_back(F->getArg(i)->getType());
|
|
return FunctionType::get(F->getReturnType(), ArgTys, F->isVarArg());
|
|
}
|
|
|
|
inline Type *toTypedPointer(Type *Ty, LLVMContext &Ctx) {
|
|
return isUntypedPointerTy(Ty)
|
|
? TypedPointerType::get(IntegerType::getInt8Ty(Ctx),
|
|
getPointerAddressSpace(Ty))
|
|
: Ty;
|
|
}
|
|
|
|
} // namespace llvm
|
|
#endif // LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H
|