diff --git a/clang/lib/CodeGen/ABIInfoImpl.h b/clang/lib/CodeGen/ABIInfoImpl.h new file mode 100644 --- /dev/null +++ b/clang/lib/CodeGen/ABIInfoImpl.h @@ -0,0 +1,56 @@ +//===- DefaultABIInfo.h -----------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_CODEGEN_ABIINFOIMPL_H +#define LLVM_CLANG_LIB_CODEGEN_ABIINFOIMPL_H + +#include "ABIInfo.h" +#include "CGCXXABI.h" + +namespace clang::CodeGen { + +/// DefaultABIInfo - The default implementation for ABI specific details. +/// This implementation provides information which results in self-consistent +/// and sensible LLVM IR generation, but does not conform to any particular ABI. +class DefaultABIInfo : public ABIInfo { +public: + DefaultABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} + + ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType RetTy) const; + + void computeInfo(CGFunctionInfo &FI) const override; + + Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty) const override; +}; + +bool isAggregateTypeForABI(QualType T); + +llvm::Type *getVAListElementType(CodeGenFunction &CGF); + +CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT, CGCXXABI &CXXABI); + +CGCXXABI::RecordArgABI getRecordArgABI(QualType T, CGCXXABI &CXXABI); + +QualType useFirstFieldIfTransparentUnion(QualType Ty); + +Address emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType ValueTy, bool IsIndirect, + TypeInfoChars ValueInfo, CharUnits SlotSizeAndAlign, + bool AllowHigherAlign, bool ForceRightAdjust = false); + +bool isEmptyField(ASTContext &Context, const FieldDecl *FD, bool AllowArrays); + +bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); + +const Type *isSingleElementStruct(QualType T, ASTContext &Context); + +} // namespace clang::CodeGen + +#endif // LLVM_CLANG_LIB_CODEGEN_ABIINFOIMPL_H diff --git a/clang/lib/CodeGen/CMakeLists.txt b/clang/lib/CodeGen/CMakeLists.txt --- a/clang/lib/CodeGen/CMakeLists.txt +++ b/clang/lib/CodeGen/CMakeLists.txt @@ -31,6 +31,10 @@ ) add_clang_library(clangCodeGen + Targets/ARC.cpp + Targets/CSKY.cpp + Targets/M68k.cpp + Targets/SPIR.cpp BackendUtil.cpp CGAtomic.cpp CGBlocks.cpp diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -13,10 +13,15 @@ #include "TargetInfo.h" #include "ABIInfo.h" +#include "ABIInfoImpl.h" #include "CGBlocks.h" #include "CGCXXABI.h" #include "CGValue.h" #include "CodeGenFunction.h" +#include "Targets/ARC.h" +#include "Targets/CSKY.h" +#include "Targets/M68k.h" +#include "Targets/SPIR.h" #include "clang/AST/Attr.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/Builtins.h" @@ -77,7 +82,7 @@ } } -static bool isAggregateTypeForABI(QualType T) { +bool CodeGen::isAggregateTypeForABI(QualType T) { return !CodeGenFunction::hasScalarEvaluationKind(T) || T->isMemberFunctionPointerType(); } @@ -100,7 +105,7 @@ return Address::invalid(); } -static llvm::Type *getVAListElementType(CodeGenFunction &CGF) { +llvm::Type *CodeGen::getVAListElementType(CodeGenFunction &CGF) { return CGF.ConvertTypeForMem( CGF.getContext().getBuiltinVaListType()->getPointeeType()); } @@ -164,8 +169,8 @@ return (VectorSize.getQuantity() > 8 && VectorSize.getQuantity() <= 16); } -static CGCXXABI::RecordArgABI getRecordArgABI(const RecordType *RT, - CGCXXABI &CXXABI) { +CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(const RecordType *RT, + CGCXXABI &CXXABI) { const CXXRecordDecl *RD = dyn_cast(RT->getDecl()); if (!RD) { if (!RT->getDecl()->canPassInRegisters()) @@ -175,8 +180,7 @@ return CXXABI.getRecordArgABI(RD); } -static CGCXXABI::RecordArgABI getRecordArgABI(QualType T, - CGCXXABI &CXXABI) { +CGCXXABI::RecordArgABI CodeGen::getRecordArgABI(QualType T, CGCXXABI &CXXABI) { const RecordType *RT = T->getAs(); if (!RT) return CGCXXABI::RAA_Default; @@ -199,7 +203,7 @@ /// Pass transparent unions as if they were the type of the first element. Sema /// should ensure that all elements of the union have the same "machine type". -static QualType useFirstFieldIfTransparentUnion(QualType Ty) { +QualType CodeGen::useFirstFieldIfTransparentUnion(QualType Ty) { if (const RecordType *UT = Ty->getAsUnionType()) { const RecordDecl *UD = UT->getDecl(); if (UD->hasAttr()) { @@ -382,12 +386,12 @@ /// \param ForceRightAdjust - Default is false. On big-endian platform and /// if the argument is smaller than a slot, set this flag will force /// right-adjust the argument in its slot irrespective of the type. -static Address emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr, - QualType ValueTy, bool IsIndirect, - TypeInfoChars ValueInfo, - CharUnits SlotSizeAndAlign, - bool AllowHigherAlign, - bool ForceRightAdjust = false) { +Address CodeGen::emitVoidPtrVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType ValueTy, bool IsIndirect, + TypeInfoChars ValueInfo, + CharUnits SlotSizeAndAlign, + bool AllowHigherAlign, + bool ForceRightAdjust) { // The size and alignment of the value that was passed directly. CharUnits DirectSize, DirectAlign; if (IsIndirect) { @@ -548,12 +552,10 @@ return Ctx.getOrInsertSyncScopeID(""); /* default sync scope */ } -static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); - /// isEmptyField - Return true iff a the field is "empty", that is it /// is an unnamed bit-field or an (array of) empty record(s). -static bool isEmptyField(ASTContext &Context, const FieldDecl *FD, - bool AllowArrays) { +bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD, + bool AllowArrays) { if (FD->isUnnamedBitfield()) return true; @@ -596,7 +598,7 @@ /// isEmptyRecord - Return true iff a structure contains only empty /// fields. Note that a structure with a flexible array member is not /// considered empty. -static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) { +bool CodeGen::isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays) { const RecordType *RT = T->getAs(); if (!RT) return false; @@ -624,7 +626,7 @@ /// /// \return The field declaration for the single non-empty field, if /// it exists. -static const Type *isSingleElementStruct(QualType T, ASTContext &Context) { +const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) { const RecordType *RT = T->getAs(); if (!RT) return nullptr; @@ -691,9 +693,8 @@ return Found; } -namespace { -Address EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr, QualType Ty, - const ABIArgInfo &AI) { +static Address EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty, const ABIArgInfo &AI) { // This default implementation defers to the llvm backend's va_arg // instruction. It can handle only passing arguments directly // (typically only handled in the backend for primitive types), or @@ -741,35 +742,25 @@ } } -/// DefaultABIInfo - The default implementation for ABI specific -/// details. This implementation provides information which results in -/// self-consistent and sensible LLVM IR generation, but does not -/// conform to any particular ABI. -class DefaultABIInfo : public ABIInfo { -public: - DefaultABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} - - ABIArgInfo classifyReturnType(QualType RetTy) const; - ABIArgInfo classifyArgumentType(QualType RetTy) const; - - void computeInfo(CGFunctionInfo &FI) const override { - if (!getCXXABI().classifyReturnType(FI)) - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); - for (auto &I : FI.arguments()) - I.info = classifyArgumentType(I.type); - } +void DefaultABIInfo::computeInfo(CGFunctionInfo &FI) const { + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + for (auto &I : FI.arguments()) + I.info = classifyArgumentType(I.type); +} - Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, - QualType Ty) const override { - return EmitVAArgInstr(CGF, VAListAddr, Ty, classifyArgumentType(Ty)); - } -}; +Address DefaultABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty) const { + return EmitVAArgInstr(CGF, VAListAddr, Ty, classifyArgumentType(Ty)); +} +namespace { class DefaultTargetCodeGenInfo : public TargetCodeGenInfo { public: DefaultTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) : TargetCodeGenInfo(std::make_unique(CGT)) {} }; +} // namespace ABIArgInfo DefaultABIInfo::classifyArgumentType(QualType Ty) const { Ty = useFirstFieldIfTransparentUnion(Ty); @@ -821,6 +812,8 @@ : ABIArgInfo::getDirect()); } +namespace { + //===----------------------------------------------------------------------===// // WebAssembly ABI Implementation // @@ -1305,7 +1298,7 @@ } }; -} +} // namespace /// Rewrite input constraint references after adding some output constraints. /// In the case where there is one output and one input and we add one output, @@ -8422,43 +8415,6 @@ return false; } -//===----------------------------------------------------------------------===// -// M68k ABI Implementation -//===----------------------------------------------------------------------===// - -namespace { - -class M68kTargetCodeGenInfo : public TargetCodeGenInfo { -public: - M68kTargetCodeGenInfo(CodeGenTypes &CGT) - : TargetCodeGenInfo(std::make_unique(CGT)) {} - void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, - CodeGen::CodeGenModule &M) const override; -}; - -} // namespace - -void M68kTargetCodeGenInfo::setTargetAttributes( - const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { - if (const auto *FD = dyn_cast_or_null(D)) { - if (const auto *attr = FD->getAttr()) { - // Handle 'interrupt' attribute: - llvm::Function *F = cast(GV); - - // Step 1: Set ISR calling convention. - F->setCallingConv(llvm::CallingConv::M68k_INTR); - - // Step 2: Add attributes goodness. - F->addFnAttr(llvm::Attribute::NoInline); - - // Step 3: Emit ISR vector alias. - unsigned Num = attr->getNumber() / 2; - llvm::GlobalAlias::create(llvm::Function::ExternalLinkage, - "__isr_" + Twine(Num), F); - } - } -} - //===----------------------------------------------------------------------===// // AVR ABI Implementation. Documented at // https://gcc.gnu.org/wiki/avr-gcc#Calling_Convention @@ -10088,142 +10044,6 @@ return false; } -// ARC ABI implementation. -namespace { - -class ARCABIInfo : public DefaultABIInfo { -public: - using DefaultABIInfo::DefaultABIInfo; - -private: - Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, - QualType Ty) const override; - - void updateState(const ABIArgInfo &Info, QualType Ty, CCState &State) const { - if (!State.FreeRegs) - return; - if (Info.isIndirect() && Info.getInReg()) - State.FreeRegs--; - else if (Info.isDirect() && Info.getInReg()) { - unsigned sz = (getContext().getTypeSize(Ty) + 31) / 32; - if (sz < State.FreeRegs) - State.FreeRegs -= sz; - else - State.FreeRegs = 0; - } - } - - void computeInfo(CGFunctionInfo &FI) const override { - CCState State(FI); - // ARC uses 8 registers to pass arguments. - State.FreeRegs = 8; - - if (!getCXXABI().classifyReturnType(FI)) - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); - updateState(FI.getReturnInfo(), FI.getReturnType(), State); - for (auto &I : FI.arguments()) { - I.info = classifyArgumentType(I.type, State.FreeRegs); - updateState(I.info, I.type, State); - } - } - - ABIArgInfo getIndirectByRef(QualType Ty, bool HasFreeRegs) const; - ABIArgInfo getIndirectByValue(QualType Ty) const; - ABIArgInfo classifyArgumentType(QualType Ty, uint8_t FreeRegs) const; - ABIArgInfo classifyReturnType(QualType RetTy) const; -}; - -class ARCTargetCodeGenInfo : public TargetCodeGenInfo { -public: - ARCTargetCodeGenInfo(CodeGenTypes &CGT) - : TargetCodeGenInfo(std::make_unique(CGT)) {} -}; - - -ABIArgInfo ARCABIInfo::getIndirectByRef(QualType Ty, bool HasFreeRegs) const { - return HasFreeRegs ? getNaturalAlignIndirectInReg(Ty) : - getNaturalAlignIndirect(Ty, false); -} - -ABIArgInfo ARCABIInfo::getIndirectByValue(QualType Ty) const { - // Compute the byval alignment. - const unsigned MinABIStackAlignInBytes = 4; - unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8; - return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true, - TypeAlign > MinABIStackAlignInBytes); -} - -Address ARCABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, - QualType Ty) const { - return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, - getContext().getTypeInfoInChars(Ty), - CharUnits::fromQuantity(4), true); -} - -ABIArgInfo ARCABIInfo::classifyArgumentType(QualType Ty, - uint8_t FreeRegs) const { - // Handle the generic C++ ABI. - const RecordType *RT = Ty->getAs(); - if (RT) { - CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); - if (RAA == CGCXXABI::RAA_Indirect) - return getIndirectByRef(Ty, FreeRegs > 0); - - if (RAA == CGCXXABI::RAA_DirectInMemory) - return getIndirectByValue(Ty); - } - - // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getDecl()->getIntegerType(); - - auto SizeInRegs = llvm::alignTo(getContext().getTypeSize(Ty), 32) / 32; - - if (isAggregateTypeForABI(Ty)) { - // Structures with flexible arrays are always indirect. - if (RT && RT->getDecl()->hasFlexibleArrayMember()) - return getIndirectByValue(Ty); - - // Ignore empty structs/unions. - if (isEmptyRecord(getContext(), Ty, true)) - return ABIArgInfo::getIgnore(); - - llvm::LLVMContext &LLVMContext = getVMContext(); - - llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext); - SmallVector Elements(SizeInRegs, Int32); - llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); - - return FreeRegs >= SizeInRegs ? - ABIArgInfo::getDirectInReg(Result) : - ABIArgInfo::getDirect(Result, 0, nullptr, false); - } - - if (const auto *EIT = Ty->getAs()) - if (EIT->getNumBits() > 64) - return getIndirectByValue(Ty); - - return isPromotableIntegerTypeForABI(Ty) - ? (FreeRegs >= SizeInRegs ? ABIArgInfo::getExtendInReg(Ty) - : ABIArgInfo::getExtend(Ty)) - : (FreeRegs >= SizeInRegs ? ABIArgInfo::getDirectInReg() - : ABIArgInfo::getDirect()); -} - -ABIArgInfo ARCABIInfo::classifyReturnType(QualType RetTy) const { - if (RetTy->isAnyComplexType()) - return ABIArgInfo::getDirectInReg(); - - // Arguments of size > 4 registers are indirect. - auto RetSize = llvm::alignTo(getContext().getTypeSize(RetTy), 32) / 32; - if (RetSize > 4) - return getIndirectByRef(RetTy, /*HasFreeRegs*/ true); - - return DefaultABIInfo::classifyReturnType(RetTy); -} - -} // End anonymous namespace. - //===----------------------------------------------------------------------===// // XCore ABI Implementation //===----------------------------------------------------------------------===// @@ -10536,126 +10356,6 @@ } } -//===----------------------------------------------------------------------===// -// Base ABI and target codegen info implementation common between SPIR and -// SPIR-V. -//===----------------------------------------------------------------------===// - -namespace { -class CommonSPIRABIInfo : public DefaultABIInfo { -public: - CommonSPIRABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) { setCCs(); } - -private: - void setCCs(); -}; - -class SPIRVABIInfo : public CommonSPIRABIInfo { -public: - SPIRVABIInfo(CodeGenTypes &CGT) : CommonSPIRABIInfo(CGT) {} - void computeInfo(CGFunctionInfo &FI) const override; - -private: - ABIArgInfo classifyKernelArgumentType(QualType Ty) const; -}; -} // end anonymous namespace -namespace { -class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo { -public: - CommonSPIRTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) - : TargetCodeGenInfo(std::make_unique(CGT)) {} - CommonSPIRTargetCodeGenInfo(std::unique_ptr ABIInfo) - : TargetCodeGenInfo(std::move(ABIInfo)) {} - - LangAS getASTAllocaAddressSpace() const override { - return getLangASFromTargetAS( - getABIInfo().getDataLayout().getAllocaAddrSpace()); - } - - unsigned getOpenCLKernelCallingConv() const override; - llvm::Type *getOpenCLType(CodeGenModule &CGM, const Type *T) const override; -}; -class SPIRVTargetCodeGenInfo : public CommonSPIRTargetCodeGenInfo { -public: - SPIRVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) - : CommonSPIRTargetCodeGenInfo(std::make_unique(CGT)) {} - void setCUDAKernelCallingConvention(const FunctionType *&FT) const override; -}; -} // End anonymous namespace. - -void CommonSPIRABIInfo::setCCs() { - assert(getRuntimeCC() == llvm::CallingConv::C); - RuntimeCC = llvm::CallingConv::SPIR_FUNC; -} - -ABIArgInfo SPIRVABIInfo::classifyKernelArgumentType(QualType Ty) const { - if (getContext().getLangOpts().CUDAIsDevice) { - // Coerce pointer arguments with default address space to CrossWorkGroup - // pointers for HIPSPV/CUDASPV. When the language mode is HIP/CUDA, the - // SPIRTargetInfo maps cuda_device to SPIR-V's CrossWorkGroup address space. - llvm::Type *LTy = CGT.ConvertType(Ty); - auto DefaultAS = getContext().getTargetAddressSpace(LangAS::Default); - auto GlobalAS = getContext().getTargetAddressSpace(LangAS::cuda_device); - auto *PtrTy = llvm::dyn_cast(LTy); - if (PtrTy && PtrTy->getAddressSpace() == DefaultAS) { - LTy = llvm::PointerType::getWithSamePointeeType(PtrTy, GlobalAS); - return ABIArgInfo::getDirect(LTy, 0, nullptr, false); - } - - // Force copying aggregate type in kernel arguments by value when - // compiling CUDA targeting SPIR-V. This is required for the object - // copied to be valid on the device. - // This behavior follows the CUDA spec - // https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#global-function-argument-processing, - // and matches the NVPTX implementation. - if (isAggregateTypeForABI(Ty)) - return getNaturalAlignIndirect(Ty, /* byval */ true); - } - return classifyArgumentType(Ty); -} - -void SPIRVABIInfo::computeInfo(CGFunctionInfo &FI) const { - // The logic is same as in DefaultABIInfo with an exception on the kernel - // arguments handling. - llvm::CallingConv::ID CC = FI.getCallingConvention(); - - if (!getCXXABI().classifyReturnType(FI)) - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); - - for (auto &I : FI.arguments()) { - if (CC == llvm::CallingConv::SPIR_KERNEL) { - I.info = classifyKernelArgumentType(I.type); - } else { - I.info = classifyArgumentType(I.type); - } - } -} - -namespace clang { -namespace CodeGen { -void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI) { - if (CGM.getTarget().getTriple().isSPIRV()) - SPIRVABIInfo(CGM.getTypes()).computeInfo(FI); - else - CommonSPIRABIInfo(CGM.getTypes()).computeInfo(FI); -} -} -} - -unsigned CommonSPIRTargetCodeGenInfo::getOpenCLKernelCallingConv() const { - return llvm::CallingConv::SPIR_KERNEL; -} - -void SPIRVTargetCodeGenInfo::setCUDAKernelCallingConvention( - const FunctionType *&FT) const { - // Convert HIP kernels to SPIR-V kernels. - if (getABIInfo().getContext().getLangOpts().HIP) { - FT = getABIInfo().getContext().adjustFunctionType( - FT, FT->getExtInfo().withCallingConv(CC_OpenCLKernel)); - return; - } -} - static bool appendType(SmallStringEnc &Enc, QualType QType, const CodeGen::CodeGenModule &CGM, TypeStringCache &TSC); @@ -10988,80 +10688,6 @@ return false; } -/// Construct a SPIR-V target extension type for the given OpenCL image type. -static llvm::Type *getSPIRVImageType(llvm::LLVMContext &Ctx, StringRef BaseType, - StringRef OpenCLName, - unsigned AccessQualifier) { - // These parameters compare to the operands of OpTypeImage (see - // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpTypeImage - // for more details). The first 6 integer parameters all default to 0, and - // will be changed to 1 only for the image type(s) that set the parameter to - // one. The 7th integer parameter is the access qualifier, which is tacked on - // at the end. - SmallVector IntParams = {0, 0, 0, 0, 0, 0}; - - // Choose the dimension of the image--this corresponds to the Dim enum in - // SPIR-V (first integer parameter of OpTypeImage). - if (OpenCLName.startswith("image2d")) - IntParams[0] = 1; // 1D - else if (OpenCLName.startswith("image3d")) - IntParams[0] = 2; // 2D - else if (OpenCLName == "image1d_buffer") - IntParams[0] = 5; // Buffer - else - assert(OpenCLName.startswith("image1d") && "Unknown image type"); - - // Set the other integer parameters of OpTypeImage if necessary. Note that the - // OpenCL image types don't provide any information for the Sampled or - // Image Format parameters. - if (OpenCLName.contains("_depth")) - IntParams[1] = 1; - if (OpenCLName.contains("_array")) - IntParams[2] = 1; - if (OpenCLName.contains("_msaa")) - IntParams[3] = 1; - - // Access qualifier - IntParams.push_back(AccessQualifier); - - return llvm::TargetExtType::get(Ctx, BaseType, {llvm::Type::getVoidTy(Ctx)}, - IntParams); -} - -llvm::Type *CommonSPIRTargetCodeGenInfo::getOpenCLType(CodeGenModule &CGM, - const Type *Ty) const { - llvm::LLVMContext &Ctx = CGM.getLLVMContext(); - if (auto *PipeTy = dyn_cast(Ty)) - return llvm::TargetExtType::get(Ctx, "spirv.Pipe", {}, - {!PipeTy->isReadOnly()}); - if (auto *BuiltinTy = dyn_cast(Ty)) { - enum AccessQualifier : unsigned { AQ_ro = 0, AQ_wo = 1, AQ_rw = 2 }; - switch (BuiltinTy->getKind()) { -#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ - case BuiltinType::Id: \ - return getSPIRVImageType(Ctx, "spirv.Image", #ImgType, AQ_##Suffix); -#include "clang/Basic/OpenCLImageTypes.def" - case BuiltinType::OCLSampler: - return llvm::TargetExtType::get(Ctx, "spirv.Sampler"); - case BuiltinType::OCLEvent: - return llvm::TargetExtType::get(Ctx, "spirv.Event"); - case BuiltinType::OCLClkEvent: - return llvm::TargetExtType::get(Ctx, "spirv.DeviceEvent"); - case BuiltinType::OCLQueue: - return llvm::TargetExtType::get(Ctx, "spirv.Queue"); - case BuiltinType::OCLReserveID: - return llvm::TargetExtType::get(Ctx, "spirv.ReserveId"); -#define INTEL_SUBGROUP_AVC_TYPE(Name, Id) \ - case BuiltinType::OCLIntelSubgroupAVC##Id: \ - return llvm::TargetExtType::get(Ctx, "spirv.Avc" #Id "INTEL"); -#include "clang/Basic/OpenCLExtensionTypes.def" - default: - return nullptr; - } - } - - return nullptr; -} //===----------------------------------------------------------------------===// // RISC-V ABI Implementation //===----------------------------------------------------------------------===// @@ -11592,165 +11218,6 @@ }; } // end anonymous namespace -//===----------------------------------------------------------------------===// -// CSKY ABI Implementation -//===----------------------------------------------------------------------===// -namespace { -class CSKYABIInfo : public DefaultABIInfo { - static const int NumArgGPRs = 4; - static const int NumArgFPRs = 4; - - static const unsigned XLen = 32; - unsigned FLen; - -public: - CSKYABIInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen) - : DefaultABIInfo(CGT), FLen(FLen) {} - - void computeInfo(CGFunctionInfo &FI) const override; - ABIArgInfo classifyArgumentType(QualType Ty, int &ArgGPRsLeft, - int &ArgFPRsLeft, - bool isReturnType = false) const; - ABIArgInfo classifyReturnType(QualType RetTy) const; - - Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, - QualType Ty) const override; -}; - -} // end anonymous namespace - -void CSKYABIInfo::computeInfo(CGFunctionInfo &FI) const { - QualType RetTy = FI.getReturnType(); - if (!getCXXABI().classifyReturnType(FI)) - FI.getReturnInfo() = classifyReturnType(RetTy); - - bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect; - - // We must track the number of GPRs used in order to conform to the CSKY - // ABI, as integer scalars passed in registers should have signext/zeroext - // when promoted. - int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs; - int ArgFPRsLeft = FLen ? NumArgFPRs : 0; - - for (auto &ArgInfo : FI.arguments()) { - ArgInfo.info = classifyArgumentType(ArgInfo.type, ArgGPRsLeft, ArgFPRsLeft); - } -} - -Address CSKYABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, - QualType Ty) const { - CharUnits SlotSize = CharUnits::fromQuantity(XLen / 8); - - // Empty records are ignored for parameter passing purposes. - if (isEmptyRecord(getContext(), Ty, true)) { - Address Addr = Address(CGF.Builder.CreateLoad(VAListAddr), - getVAListElementType(CGF), SlotSize); - Addr = CGF.Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(Ty)); - return Addr; - } - - auto TInfo = getContext().getTypeInfoInChars(Ty); - - return emitVoidPtrVAArg(CGF, VAListAddr, Ty, false, TInfo, SlotSize, - /*AllowHigherAlign=*/true); -} - -ABIArgInfo CSKYABIInfo::classifyArgumentType(QualType Ty, int &ArgGPRsLeft, - int &ArgFPRsLeft, - bool isReturnType) const { - assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow"); - Ty = useFirstFieldIfTransparentUnion(Ty); - - // Structures with either a non-trivial destructor or a non-trivial - // copy constructor are always passed indirectly. - if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { - if (ArgGPRsLeft) - ArgGPRsLeft -= 1; - return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA == - CGCXXABI::RAA_DirectInMemory); - } - - // Ignore empty structs/unions. - if (isEmptyRecord(getContext(), Ty, true)) - return ABIArgInfo::getIgnore(); - - if (!Ty->getAsUnionType()) - if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) - return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); - - uint64_t Size = getContext().getTypeSize(Ty); - // Pass floating point values via FPRs if possible. - if (Ty->isFloatingType() && !Ty->isComplexType() && FLen >= Size && - ArgFPRsLeft) { - ArgFPRsLeft--; - return ABIArgInfo::getDirect(); - } - - // Complex types for the hard float ABI must be passed direct rather than - // using CoerceAndExpand. - if (Ty->isComplexType() && FLen && !isReturnType) { - QualType EltTy = Ty->castAs()->getElementType(); - if (getContext().getTypeSize(EltTy) <= FLen) { - ArgFPRsLeft -= 2; - return ABIArgInfo::getDirect(); - } - } - - if (!isAggregateTypeForABI(Ty)) { - // Treat an enum type as its underlying type. - if (const EnumType *EnumTy = Ty->getAs()) - Ty = EnumTy->getDecl()->getIntegerType(); - - // All integral types are promoted to XLen width, unless passed on the - // stack. - if (Size < XLen && Ty->isIntegralOrEnumerationType()) - return ABIArgInfo::getExtend(Ty); - - if (const auto *EIT = Ty->getAs()) { - if (EIT->getNumBits() < XLen) - return ABIArgInfo::getExtend(Ty); - } - - return ABIArgInfo::getDirect(); - } - - // For argument type, the first 4*XLen parts of aggregate will be passed - // in registers, and the rest will be passed in stack. - // So we can coerce to integers directly and let backend handle it correctly. - // For return type, aggregate which <= 2*XLen will be returned in registers. - // Otherwise, aggregate will be returned indirectly. - if (!isReturnType || (isReturnType && Size <= 2 * XLen)) { - if (Size <= XLen) { - return ABIArgInfo::getDirect( - llvm::IntegerType::get(getVMContext(), XLen)); - } else { - return ABIArgInfo::getDirect(llvm::ArrayType::get( - llvm::IntegerType::get(getVMContext(), XLen), (Size + 31) / XLen)); - } - } - return getNaturalAlignIndirect(Ty, /*ByVal=*/false); -} - -ABIArgInfo CSKYABIInfo::classifyReturnType(QualType RetTy) const { - if (RetTy->isVoidType()) - return ABIArgInfo::getIgnore(); - - int ArgGPRsLeft = 2; - int ArgFPRsLeft = FLen ? 1 : 0; - - // The rules for return and argument types are the same, so defer to - // classifyArgumentType. - return classifyArgumentType(RetTy, ArgGPRsLeft, ArgFPRsLeft, true); -} - -namespace { -class CSKYTargetCodeGenInfo : public TargetCodeGenInfo { -public: - CSKYTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen) - : TargetCodeGenInfo(std::make_unique(CGT, FLen)) {} -}; -} // end anonymous namespace - //===----------------------------------------------------------------------===// // BPF ABI Implementation //===----------------------------------------------------------------------===// diff --git a/clang/lib/CodeGen/Targets/ARC.h b/clang/lib/CodeGen/Targets/ARC.h new file mode 100644 --- /dev/null +++ b/clang/lib/CodeGen/Targets/ARC.h @@ -0,0 +1,23 @@ +//===- ARC.h ----------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_CODEGEN_TARGETS_ARC_H +#define LLVM_CLANG_LIB_CODEGEN_TARGETS_ARC_H + +#include "TargetInfo.h" + +namespace clang::CodeGen { + +class ARCTargetCodeGenInfo : public TargetCodeGenInfo { +public: + explicit ARCTargetCodeGenInfo(CodeGenTypes &CGT); +}; + +} // namespace clang::CodeGen + +#endif // LLVM_CLANG_LIB_CODEGEN_TARGETS_ARC_H diff --git a/clang/lib/CodeGen/Targets/ARC.cpp b/clang/lib/CodeGen/Targets/ARC.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/CodeGen/Targets/ARC.cpp @@ -0,0 +1,153 @@ +//===- ARC.cpp ------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// ARC ABI Implementation +//===----------------------------------------------------------------------===// + +#include "ARC.h" +#include "ABIInfoImpl.h" + +using namespace clang; +using namespace clang::CodeGen; + +namespace { +class ARCABIInfo : public DefaultABIInfo { + struct CCState { + unsigned FreeRegs; + }; + +public: + explicit ARCABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} + + void computeInfo(CGFunctionInfo &FI) const override; + + Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty) const override; + +private: + void updateState(const ABIArgInfo &Info, QualType Ty, CCState &State) const; + + ABIArgInfo getIndirectByRef(QualType Ty, bool HasFreeRegs) const; + ABIArgInfo getIndirectByValue(QualType Ty) const; + ABIArgInfo classifyArgumentType(QualType Ty, uint8_t FreeRegs) const; + ABIArgInfo classifyReturnType(QualType RetTy) const; +}; +} // namespace + +void ARCABIInfo::updateState(const ABIArgInfo &Info, QualType Ty, + ARCABIInfo::CCState &State) const { + if (!State.FreeRegs) + return; + if (Info.isIndirect() && Info.getInReg()) { + State.FreeRegs--; + } else if (Info.isDirect() && Info.getInReg()) { + unsigned sz = (getContext().getTypeSize(Ty) + 31) / 32; + if (sz < State.FreeRegs) + State.FreeRegs -= sz; + else + State.FreeRegs = 0; + } +} + +ABIArgInfo ARCABIInfo::getIndirectByRef(QualType Ty, bool HasFreeRegs) const { + return HasFreeRegs ? getNaturalAlignIndirectInReg(Ty) + : getNaturalAlignIndirect(Ty, false); +} + +ABIArgInfo ARCABIInfo::getIndirectByValue(QualType Ty) const { + // Compute the byval alignment. + const unsigned MinABIStackAlignInBytes = 4; + unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8; + return ABIArgInfo::getIndirect(CharUnits::fromQuantity(4), /*ByVal=*/true, + TypeAlign > MinABIStackAlignInBytes); +} + +ABIArgInfo ARCABIInfo::classifyArgumentType(QualType Ty, + uint8_t FreeRegs) const { + // Handle the generic C++ ABI. + const RecordType *RT = Ty->getAs(); + if (RT) { + CGCXXABI::RecordArgABI RAA = getRecordArgABI(RT, getCXXABI()); + if (RAA == CGCXXABI::RAA_Indirect) + return getIndirectByRef(Ty, FreeRegs > 0); + + if (RAA == CGCXXABI::RAA_DirectInMemory) + return getIndirectByValue(Ty); + } + + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs()) + Ty = EnumTy->getDecl()->getIntegerType(); + + auto SizeInRegs = llvm::alignTo(getContext().getTypeSize(Ty), 32) / 32; + + if (isAggregateTypeForABI(Ty)) { + // Structures with flexible arrays are always indirect. + if (RT && RT->getDecl()->hasFlexibleArrayMember()) + return getIndirectByValue(Ty); + + // Ignore empty structs/unions. + if (isEmptyRecord(getContext(), Ty, true)) + return ABIArgInfo::getIgnore(); + + llvm::LLVMContext &LLVMContext = getVMContext(); + + llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext); + SmallVector Elements(SizeInRegs, Int32); + llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); + + return FreeRegs >= SizeInRegs + ? ABIArgInfo::getDirectInReg(Result) + : ABIArgInfo::getDirect(Result, 0, nullptr, false); + } + + if (const auto *EIT = Ty->getAs()) + if (EIT->getNumBits() > 64) + return getIndirectByValue(Ty); + + return isPromotableIntegerTypeForABI(Ty) + ? (FreeRegs >= SizeInRegs ? ABIArgInfo::getExtendInReg(Ty) + : ABIArgInfo::getExtend(Ty)) + : (FreeRegs >= SizeInRegs ? ABIArgInfo::getDirectInReg() + : ABIArgInfo::getDirect()); +} + +ABIArgInfo ARCABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isAnyComplexType()) + return ABIArgInfo::getDirectInReg(); + + // Arguments of size > 4 registers are indirect. + auto RetSize = llvm::alignTo(getContext().getTypeSize(RetTy), 32) / 32; + if (RetSize > 4) + return getIndirectByRef(RetTy, /*HasFreeRegs*/ true); + + return DefaultABIInfo::classifyReturnType(RetTy); +} + +void ARCABIInfo::computeInfo(CGFunctionInfo &FI) const { + CCState State; + // ARC uses 8 registers to pass arguments. + State.FreeRegs = 8; + + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + updateState(FI.getReturnInfo(), FI.getReturnType(), State); + for (auto &I : FI.arguments()) { + I.info = classifyArgumentType(I.type, State.FreeRegs); + updateState(I.info, I.type, State); + } +} + +Address ARCABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty) const { + return emitVoidPtrVAArg(CGF, VAListAddr, Ty, /*indirect*/ false, + getContext().getTypeInfoInChars(Ty), + CharUnits::fromQuantity(4), true); +} + +ARCTargetCodeGenInfo::ARCTargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(std::make_unique(CGT)) {} diff --git a/clang/lib/CodeGen/Targets/CSKY.h b/clang/lib/CodeGen/Targets/CSKY.h new file mode 100644 --- /dev/null +++ b/clang/lib/CodeGen/Targets/CSKY.h @@ -0,0 +1,23 @@ +//===- CSKY.h ---------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_CODEGEN_TARGETS_CSKY_H +#define LLVM_CLANG_LIB_CODEGEN_TARGETS_CSKY_H + +#include "TargetInfo.h" + +namespace clang::CodeGen { + +class CSKYTargetCodeGenInfo : public TargetCodeGenInfo { +public: + CSKYTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen); +}; + +} // namespace clang::CodeGen + +#endif // LLVM_CLANG_LIB_CODEGEN_TARGETS_CSKY_H diff --git a/clang/lib/CodeGen/Targets/CSKY.cpp b/clang/lib/CodeGen/Targets/CSKY.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/CodeGen/Targets/CSKY.cpp @@ -0,0 +1,164 @@ +//===- CSKY.cpp -----------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// CSKY ABI Implementation +//===----------------------------------------------------------------------===// + +#include "CSKY.h" +#include "ABIInfoImpl.h" + +using namespace clang; +using namespace clang::CodeGen; + +namespace { +class CSKYABIInfo : public DefaultABIInfo { + static const int NumArgGPRs = 4; + static const int NumArgFPRs = 4; + + static const unsigned XLen = 32; + unsigned FLen; + +public: + CSKYABIInfo(CodeGen::CodeGenTypes &CGT, unsigned FLen) + : DefaultABIInfo(CGT), FLen(FLen) {} + + void computeInfo(CGFunctionInfo &FI) const override; + + Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty) const override; + +private: + ABIArgInfo classifyArgumentType(QualType Ty, int &ArgGPRsLeft, + int &ArgFPRsLeft, + bool isReturnType = false) const; + ABIArgInfo classifyReturnType(QualType RetTy) const; +}; +} // namespace + +void CSKYABIInfo::computeInfo(CGFunctionInfo &FI) const { + QualType RetTy = FI.getReturnType(); + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(RetTy); + + bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect; + + // We must track the number of GPRs used in order to conform to the CSKY + // ABI, as integer scalars passed in registers should have signext/zeroext + // when promoted. + int ArgGPRsLeft = IsRetIndirect ? NumArgGPRs - 1 : NumArgGPRs; + int ArgFPRsLeft = FLen ? NumArgFPRs : 0; + + for (auto &ArgInfo : FI.arguments()) + ArgInfo.info = classifyArgumentType(ArgInfo.type, ArgGPRsLeft, ArgFPRsLeft); +} + +Address CSKYABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty) const { + CharUnits SlotSize = CharUnits::fromQuantity(XLen / 8); + + // Empty records are ignored for parameter passing purposes. + if (isEmptyRecord(getContext(), Ty, true)) { + Address Addr = Address(CGF.Builder.CreateLoad(VAListAddr), + getVAListElementType(CGF), SlotSize); + Addr = CGF.Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(Ty)); + return Addr; + } + + auto TInfo = getContext().getTypeInfoInChars(Ty); + + return emitVoidPtrVAArg(CGF, VAListAddr, Ty, false, TInfo, SlotSize, + /*AllowHigherAlign=*/true); +} + +ABIArgInfo CSKYABIInfo::classifyArgumentType(QualType Ty, int &ArgGPRsLeft, + int &ArgFPRsLeft, + bool isReturnType) const { + assert(ArgGPRsLeft <= NumArgGPRs && "Arg GPR tracking underflow"); + Ty = useFirstFieldIfTransparentUnion(Ty); + + // Structures with either a non-trivial destructor or a non-trivial + // copy constructor are always passed indirectly. + if (CGCXXABI::RecordArgABI RAA = getRecordArgABI(Ty, getCXXABI())) { + if (ArgGPRsLeft) + ArgGPRsLeft -= 1; + return getNaturalAlignIndirect(Ty, /*ByVal=*/RAA == + CGCXXABI::RAA_DirectInMemory); + } + + // Ignore empty structs/unions. + if (isEmptyRecord(getContext(), Ty, true)) + return ABIArgInfo::getIgnore(); + + if (!Ty->getAsUnionType()) + if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) + return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); + + uint64_t Size = getContext().getTypeSize(Ty); + // Pass floating point values via FPRs if possible. + if (Ty->isFloatingType() && !Ty->isComplexType() && FLen >= Size && + ArgFPRsLeft) { + ArgFPRsLeft--; + return ABIArgInfo::getDirect(); + } + + // Complex types for the hard float ABI must be passed direct rather than + // using CoerceAndExpand. + if (Ty->isComplexType() && FLen && !isReturnType) { + QualType EltTy = Ty->castAs()->getElementType(); + if (getContext().getTypeSize(EltTy) <= FLen) { + ArgFPRsLeft -= 2; + return ABIArgInfo::getDirect(); + } + } + + if (!isAggregateTypeForABI(Ty)) { + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs()) + Ty = EnumTy->getDecl()->getIntegerType(); + + // All integral types are promoted to XLen width, unless passed on the + // stack. + if (Size < XLen && Ty->isIntegralOrEnumerationType()) + return ABIArgInfo::getExtend(Ty); + + if (const auto *EIT = Ty->getAs()) + if (EIT->getNumBits() < XLen) + return ABIArgInfo::getExtend(Ty); + + return ABIArgInfo::getDirect(); + } + + // For argument type, the first 4*XLen parts of aggregate will be passed + // in registers, and the rest will be passed in stack. + // So we can coerce to integers directly and let backend handle it correctly. + // For return type, aggregate which <= 2*XLen will be returned in registers. + // Otherwise, aggregate will be returned indirectly. + if (!isReturnType || (isReturnType && Size <= 2 * XLen)) { + if (Size <= XLen) { + return ABIArgInfo::getDirect( + llvm::IntegerType::get(getVMContext(), XLen)); + } + return ABIArgInfo::getDirect(llvm::ArrayType::get( + llvm::IntegerType::get(getVMContext(), XLen), (Size + 31) / XLen)); + } + return getNaturalAlignIndirect(Ty, /*ByVal=*/false); +} + +ABIArgInfo CSKYABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isVoidType()) + return ABIArgInfo::getIgnore(); + + int ArgGPRsLeft = 2; + int ArgFPRsLeft = FLen ? 1 : 0; + + // The rules for return and argument types are the same, so defer to + // classifyArgumentType. + return classifyArgumentType(RetTy, ArgGPRsLeft, ArgFPRsLeft, true); +} + +CSKYTargetCodeGenInfo::CSKYTargetCodeGenInfo(CodeGenTypes &CGT, unsigned FLen) + : TargetCodeGenInfo(std::make_unique(CGT, FLen)) {} diff --git a/clang/lib/CodeGen/Targets/M68k.h b/clang/lib/CodeGen/Targets/M68k.h new file mode 100644 --- /dev/null +++ b/clang/lib/CodeGen/Targets/M68k.h @@ -0,0 +1,26 @@ +//===- M68k.h ---------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_CODEGEN_TARGET_M68K_H +#define LLVM_CLANG_LIB_CODEGEN_TARGET_M68K_H + +#include "TargetInfo.h" + +namespace clang::CodeGen { + +class M68kTargetCodeGenInfo : public TargetCodeGenInfo { +public: + explicit M68kTargetCodeGenInfo(CodeGenTypes &CGT); + + void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, + CodeGen::CodeGenModule &M) const override; +}; + +} // namespace clang::CodeGen + +#endif // LLVM_CLANG_LIB_CODEGEN_TARGET_M68K_H diff --git a/clang/lib/CodeGen/Targets/M68k.cpp b/clang/lib/CodeGen/Targets/M68k.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/CodeGen/Targets/M68k.cpp @@ -0,0 +1,39 @@ +//===- M68k.cpp -----------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// M68k ABI Implementation +//===----------------------------------------------------------------------===// + +#include "M68k.h" +#include "ABIInfoImpl.h" + +using namespace clang; +using namespace clang::CodeGen; + +M68kTargetCodeGenInfo::M68kTargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(std::make_unique(CGT)) {} + +void M68kTargetCodeGenInfo::setTargetAttributes( + const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &M) const { + if (const auto *FD = dyn_cast_or_null(D)) { + if (const auto *attr = FD->getAttr()) { + // Handle 'interrupt' attribute: + llvm::Function *F = cast(GV); + + // Step 1: Set ISR calling convention. + F->setCallingConv(llvm::CallingConv::M68k_INTR); + + // Step 2: Add attributes goodness. + F->addFnAttr(llvm::Attribute::NoInline); + + // Step 3: Emit ISR vector alias. + unsigned Num = attr->getNumber() / 2; + llvm::GlobalAlias::create(llvm::Function::ExternalLinkage, + "__isr_" + Twine(Num), F); + } + } +} diff --git a/clang/lib/CodeGen/Targets/SPIR.h b/clang/lib/CodeGen/Targets/SPIR.h new file mode 100644 --- /dev/null +++ b/clang/lib/CodeGen/Targets/SPIR.h @@ -0,0 +1,37 @@ +//===- SPIR.h ---------------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_LIB_CODEGEN_TARGETS_SPIR_H +#define CLANG_LIB_CODEGEN_TARGETS_SPIR_H + +#include "TargetInfo.h" + +namespace clang::CodeGen { + +class CommonSPIRTargetCodeGenInfo : public TargetCodeGenInfo { +public: + explicit CommonSPIRTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT); + explicit CommonSPIRTargetCodeGenInfo(std::unique_ptr ABIInfo); + + LangAS getASTAllocaAddressSpace() const override; + + unsigned getOpenCLKernelCallingConv() const override; + + llvm::Type *getOpenCLType(CodeGenModule &CGM, const Type *T) const override; +}; + +class SPIRVTargetCodeGenInfo : public CommonSPIRTargetCodeGenInfo { +public: + explicit SPIRVTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT); + + void setCUDAKernelCallingConvention(const FunctionType *&FT) const override; +}; + +} // namespace clang::CodeGen + +#endif // CLANG_LIB_CODEGEN_TARGETS_SPIR_H diff --git a/clang/lib/CodeGen/Targets/SPIR.cpp b/clang/lib/CodeGen/Targets/SPIR.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/CodeGen/Targets/SPIR.cpp @@ -0,0 +1,201 @@ +//===- SPIR.cpp -----------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// Base ABI and target codegen info implementation common between SPIR and +// SPIR-V. +//===----------------------------------------------------------------------===// + +#include "SPIR.h" +#include "ABIInfoImpl.h" + +using namespace clang; +using namespace clang::CodeGen; + +//===----------------------------------------------------------------------===// + +namespace { +class CommonSPIRABIInfo : public DefaultABIInfo { +public: + explicit CommonSPIRABIInfo(CodeGenTypes &CGT) : DefaultABIInfo(CGT) { + setCCs(); + } + +private: + void setCCs(); +}; + +class SPIRVABIInfo : public CommonSPIRABIInfo { +public: + explicit SPIRVABIInfo(CodeGenTypes &CGT) : CommonSPIRABIInfo(CGT) {} + + void computeInfo(CGFunctionInfo &FI) const override; + +private: + ABIArgInfo classifyKernelArgumentType(QualType Ty) const; +}; +} // namespace + +void CommonSPIRABIInfo::setCCs() { + assert(getRuntimeCC() == llvm::CallingConv::C); + RuntimeCC = llvm::CallingConv::SPIR_FUNC; +} + +ABIArgInfo SPIRVABIInfo::classifyKernelArgumentType(QualType Ty) const { + if (getContext().getLangOpts().CUDAIsDevice) { + // Coerce pointer arguments with default address space to CrossWorkGroup + // pointers for HIPSPV/CUDASPV. When the language mode is HIP/CUDA, the + // SPIRTargetInfo maps cuda_device to SPIR-V's CrossWorkGroup address space. + llvm::Type *LTy = CGT.ConvertType(Ty); + auto DefaultAS = getContext().getTargetAddressSpace(LangAS::Default); + auto GlobalAS = getContext().getTargetAddressSpace(LangAS::cuda_device); + auto *PtrTy = llvm::dyn_cast(LTy); + if (PtrTy && PtrTy->getAddressSpace() == DefaultAS) { + LTy = llvm::PointerType::getWithSamePointeeType(PtrTy, GlobalAS); + return ABIArgInfo::getDirect(LTy, 0, nullptr, false); + } + + // Force copying aggregate type in kernel arguments by value when + // compiling CUDA targeting SPIR-V. This is required for the object + // copied to be valid on the device. + // This behavior follows the CUDA spec + // https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#global-function-argument-processing, + // and matches the NVPTX implementation. + if (isAggregateTypeForABI(Ty)) + return getNaturalAlignIndirect(Ty, /* byval */ true); + } + return classifyArgumentType(Ty); +} + +void SPIRVABIInfo::computeInfo(CGFunctionInfo &FI) const { + // The logic is same as in DefaultABIInfo with an exception on the kernel + // arguments handling. + llvm::CallingConv::ID CC = FI.getCallingConvention(); + + if (!getCXXABI().classifyReturnType(FI)) + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + + for (auto &I : FI.arguments()) { + if (CC == llvm::CallingConv::SPIR_KERNEL) { + I.info = classifyKernelArgumentType(I.type); + } else { + I.info = classifyArgumentType(I.type); + } + } +} + +CommonSPIRTargetCodeGenInfo::CommonSPIRTargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(std::make_unique(CGT)) {} + +CommonSPIRTargetCodeGenInfo::CommonSPIRTargetCodeGenInfo( + std::unique_ptr ABIInfo) + : TargetCodeGenInfo(std::move(ABIInfo)) {} + +LangAS CommonSPIRTargetCodeGenInfo::getASTAllocaAddressSpace() const { + return getLangASFromTargetAS( + getABIInfo().getDataLayout().getAllocaAddrSpace()); +} + +unsigned CommonSPIRTargetCodeGenInfo::getOpenCLKernelCallingConv() const { + return llvm::CallingConv::SPIR_KERNEL; +} + +/// Construct a SPIR-V target extension type for the given OpenCL image type. +static llvm::Type *getSPIRVImageType(llvm::LLVMContext &Ctx, StringRef BaseType, + StringRef OpenCLName, + unsigned AccessQualifier) { + // These parameters compare to the operands of OpTypeImage (see + // https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#OpTypeImage + // for more details). The first 6 integer parameters all default to 0, and + // will be changed to 1 only for the image type(s) that set the parameter to + // one. The 7th integer parameter is the access qualifier, which is tacked on + // at the end. + SmallVector IntParams = {0, 0, 0, 0, 0, 0}; + + // Choose the dimension of the image--this corresponds to the Dim enum in + // SPIR-V (first integer parameter of OpTypeImage). + if (OpenCLName.startswith("image2d")) + IntParams[0] = 1; // 1D + else if (OpenCLName.startswith("image3d")) + IntParams[0] = 2; // 2D + else if (OpenCLName == "image1d_buffer") + IntParams[0] = 5; // Buffer + else + assert(OpenCLName.startswith("image1d") && "Unknown image type"); + + // Set the other integer parameters of OpTypeImage if necessary. Note that the + // OpenCL image types don't provide any information for the Sampled or + // Image Format parameters. + if (OpenCLName.contains("_depth")) + IntParams[1] = 1; + if (OpenCLName.contains("_array")) + IntParams[2] = 1; + if (OpenCLName.contains("_msaa")) + IntParams[3] = 1; + + // Access qualifier + IntParams.push_back(AccessQualifier); + + return llvm::TargetExtType::get(Ctx, BaseType, {llvm::Type::getVoidTy(Ctx)}, + IntParams); +} + +llvm::Type *CommonSPIRTargetCodeGenInfo::getOpenCLType(CodeGenModule &CGM, + const Type *Ty) const { + llvm::LLVMContext &Ctx = CGM.getLLVMContext(); + if (auto *PipeTy = dyn_cast(Ty)) + return llvm::TargetExtType::get(Ctx, "spirv.Pipe", {}, + {!PipeTy->isReadOnly()}); + if (auto *BuiltinTy = dyn_cast(Ty)) { + enum AccessQualifier : unsigned { AQ_ro = 0, AQ_wo = 1, AQ_rw = 2 }; + switch (BuiltinTy->getKind()) { +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ + case BuiltinType::Id: \ + return getSPIRVImageType(Ctx, "spirv.Image", #ImgType, AQ_##Suffix); +#include "clang/Basic/OpenCLImageTypes.def" + case BuiltinType::OCLSampler: + return llvm::TargetExtType::get(Ctx, "spirv.Sampler"); + case BuiltinType::OCLEvent: + return llvm::TargetExtType::get(Ctx, "spirv.Event"); + case BuiltinType::OCLClkEvent: + return llvm::TargetExtType::get(Ctx, "spirv.DeviceEvent"); + case BuiltinType::OCLQueue: + return llvm::TargetExtType::get(Ctx, "spirv.Queue"); + case BuiltinType::OCLReserveID: + return llvm::TargetExtType::get(Ctx, "spirv.ReserveId"); +#define INTEL_SUBGROUP_AVC_TYPE(Name, Id) \ + case BuiltinType::OCLIntelSubgroupAVC##Id: \ + return llvm::TargetExtType::get(Ctx, "spirv.Avc" #Id "INTEL"); +#include "clang/Basic/OpenCLExtensionTypes.def" + default: + return nullptr; + } + } + + return nullptr; +} + +SPIRVTargetCodeGenInfo::SPIRVTargetCodeGenInfo(CodeGenTypes &CGT) + : CommonSPIRTargetCodeGenInfo(std::make_unique(CGT)) {} + +void SPIRVTargetCodeGenInfo::setCUDAKernelCallingConvention( + const FunctionType *&FT) const { + // Convert HIP kernels to SPIR-V kernels. + if (getABIInfo().getContext().getLangOpts().HIP) { + FT = getABIInfo().getContext().adjustFunctionType( + FT, FT->getExtInfo().withCallingConv(CC_OpenCLKernel)); + return; + } +} + +namespace clang::CodeGen { +void computeSPIRKernelABIInfo(CodeGenModule &CGM, CGFunctionInfo &FI) { + if (CGM.getTarget().getTriple().isSPIRV()) + SPIRVABIInfo(CGM.getTypes()).computeInfo(FI); + else + CommonSPIRABIInfo(CGM.getTypes()).computeInfo(FI); +} +} // namespace clang::CodeGen