|  | //===---- TargetInfo.cpp - Encapsulate target details -----------*- 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 | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // These classes wrap the information about a call or function | 
|  | // definition used to handle ABI compliancy. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "TargetInfo.h" | 
|  | #include "ABIInfo.h" | 
|  | #include "ABIInfoImpl.h" | 
|  | #include "CodeGenFunction.h" | 
|  | #include "clang/Basic/CodeGenOptions.h" | 
|  | #include "clang/CodeGen/CGFunctionInfo.h" | 
|  | #include "llvm/ADT/StringExtras.h" | 
|  | #include "llvm/ADT/Twine.h" | 
|  | #include "llvm/IR/Function.h" | 
|  | #include "llvm/IR/Type.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  |  | 
|  | using namespace clang; | 
|  | using namespace CodeGen; | 
|  |  | 
|  | LLVM_DUMP_METHOD void ABIArgInfo::dump() const { | 
|  | raw_ostream &OS = llvm::errs(); | 
|  | OS << "(ABIArgInfo Kind="; | 
|  | switch (TheKind) { | 
|  | case Direct: | 
|  | OS << "Direct Type="; | 
|  | if (llvm::Type *Ty = getCoerceToType()) | 
|  | Ty->print(OS); | 
|  | else | 
|  | OS << "null"; | 
|  | break; | 
|  | case Extend: | 
|  | OS << "Extend"; | 
|  | break; | 
|  | case Ignore: | 
|  | OS << "Ignore"; | 
|  | break; | 
|  | case InAlloca: | 
|  | OS << "InAlloca Offset=" << getInAllocaFieldIndex(); | 
|  | break; | 
|  | case Indirect: | 
|  | OS << "Indirect Align=" << getIndirectAlign().getQuantity() | 
|  | << " ByVal=" << getIndirectByVal() | 
|  | << " Realign=" << getIndirectRealign(); | 
|  | break; | 
|  | case IndirectAliased: | 
|  | OS << "Indirect Align=" << getIndirectAlign().getQuantity() | 
|  | << " AadrSpace=" << getIndirectAddrSpace() | 
|  | << " Realign=" << getIndirectRealign(); | 
|  | break; | 
|  | case Expand: | 
|  | OS << "Expand"; | 
|  | break; | 
|  | case CoerceAndExpand: | 
|  | OS << "CoerceAndExpand Type="; | 
|  | getCoerceAndExpandType()->print(OS); | 
|  | break; | 
|  | case TargetSpecific: | 
|  | OS << "TargetSpecific Type="; | 
|  | if (llvm::Type *Ty = getCoerceToType()) | 
|  | Ty->print(OS); | 
|  | else | 
|  | OS << "null"; | 
|  | break; | 
|  | } | 
|  | OS << ")\n"; | 
|  | } | 
|  |  | 
|  | TargetCodeGenInfo::TargetCodeGenInfo(std::unique_ptr<ABIInfo> Info) | 
|  | : Info(std::move(Info)) {} | 
|  |  | 
|  | TargetCodeGenInfo::~TargetCodeGenInfo() = default; | 
|  |  | 
|  | // If someone can figure out a general rule for this, that would be great. | 
|  | // It's probably just doomed to be platform-dependent, though. | 
|  | unsigned TargetCodeGenInfo::getSizeOfUnwindException() const { | 
|  | if (getABIInfo().getCodeGenOpts().hasSEHExceptions()) | 
|  | return getABIInfo().getDataLayout().getPointerSizeInBits() > 32 ? 64 : 48; | 
|  | // Verified for: | 
|  | //   x86-64     FreeBSD, Linux, Darwin | 
|  | //   x86-32     FreeBSD, Linux, Darwin | 
|  | //   PowerPC    Linux | 
|  | //   ARM        Darwin (*not* EABI) | 
|  | //   AArch64    Linux | 
|  | return 32; | 
|  | } | 
|  |  | 
|  | bool TargetCodeGenInfo::isNoProtoCallVariadic(const CallArgList &args, | 
|  | const FunctionNoProtoType *fnType) const { | 
|  | // The following conventions are known to require this to be false: | 
|  | //   x86_stdcall | 
|  | //   MIPS | 
|  | // For everything else, we just prefer false unless we opt out. | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void | 
|  | TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib, | 
|  | llvm::SmallString<24> &Opt) const { | 
|  | // This assumes the user is passing a library name like "rt" instead of a | 
|  | // filename like "librt.a/so", and that they don't care whether it's static or | 
|  | // dynamic. | 
|  | Opt = "-l"; | 
|  | Opt += Lib; | 
|  | } | 
|  |  | 
|  | unsigned TargetCodeGenInfo::getDeviceKernelCallingConv() const { | 
|  | if (getABIInfo().getContext().getLangOpts().OpenCL) { | 
|  | // Device kernels are called via an explicit runtime API with arguments, | 
|  | // such as set with clSetKernelArg() for OpenCL, not as normal | 
|  | // sub-functions. Return SPIR_KERNEL by default as the kernel calling | 
|  | // convention to ensure the fingerprint is fixed such way that each kernel | 
|  | // argument gets one matching argument in the produced kernel function | 
|  | // argument list to enable feasible implementation of clSetKernelArg() with | 
|  | // aggregates etc. In case we would use the default C calling conv here, | 
|  | // clSetKernelArg() might break depending on the target-specific | 
|  | // conventions; different targets might split structs passed as values | 
|  | // to multiple function arguments etc. | 
|  | return llvm::CallingConv::SPIR_KERNEL; | 
|  | } | 
|  | llvm_unreachable("Unknown kernel calling convention"); | 
|  | } | 
|  |  | 
|  | void TargetCodeGenInfo::setOCLKernelStubCallingConvention( | 
|  | const FunctionType *&FT) const { | 
|  | FT = getABIInfo().getContext().adjustFunctionType( | 
|  | FT, FT->getExtInfo().withCallingConv(CC_C)); | 
|  | } | 
|  |  | 
|  | llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM, | 
|  | llvm::PointerType *T, QualType QT) const { | 
|  | return llvm::ConstantPointerNull::get(T); | 
|  | } | 
|  |  | 
|  | LangAS TargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM, | 
|  | const VarDecl *D) const { | 
|  | assert(!CGM.getLangOpts().OpenCL && | 
|  | !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) && | 
|  | "Address space agnostic languages only"); | 
|  | return D ? D->getType().getAddressSpace() : LangAS::Default; | 
|  | } | 
|  |  | 
|  | llvm::Value *TargetCodeGenInfo::performAddrSpaceCast( | 
|  | CodeGen::CodeGenFunction &CGF, llvm::Value *Src, LangAS SrcAddr, | 
|  | llvm::Type *DestTy, bool isNonNull) const { | 
|  | // Since target may map different address spaces in AST to the same address | 
|  | // space, an address space conversion may end up as a bitcast. | 
|  | if (auto *C = dyn_cast<llvm::Constant>(Src)) | 
|  | return performAddrSpaceCast(CGF.CGM, C, SrcAddr, DestTy); | 
|  | // Try to preserve the source's name to make IR more readable. | 
|  | return CGF.Builder.CreateAddrSpaceCast( | 
|  | Src, DestTy, Src->hasName() ? Src->getName() + ".ascast" : ""); | 
|  | } | 
|  |  | 
|  | llvm::Constant * | 
|  | TargetCodeGenInfo::performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *Src, | 
|  | LangAS SrcAddr, | 
|  | llvm::Type *DestTy) const { | 
|  | // Since target may map different address spaces in AST to the same address | 
|  | // space, an address space conversion may end up as a bitcast. | 
|  | return llvm::ConstantExpr::getPointerCast(Src, DestTy); | 
|  | } | 
|  |  | 
|  | llvm::SyncScope::ID | 
|  | TargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &LangOpts, | 
|  | SyncScope Scope, | 
|  | llvm::AtomicOrdering Ordering, | 
|  | llvm::LLVMContext &Ctx) const { | 
|  | return Ctx.getOrInsertSyncScopeID(""); /* default sync scope */ | 
|  | } | 
|  |  | 
|  | void TargetCodeGenInfo::addStackProbeTargetAttributes( | 
|  | const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { | 
|  | if (llvm::Function *Fn = dyn_cast_or_null<llvm::Function>(GV)) { | 
|  | if (CGM.getCodeGenOpts().StackProbeSize != 4096) | 
|  | Fn->addFnAttr("stack-probe-size", | 
|  | llvm::utostr(CGM.getCodeGenOpts().StackProbeSize)); | 
|  | if (CGM.getCodeGenOpts().NoStackArgProbe) | 
|  | Fn->addFnAttr("no-stack-arg-probe"); | 
|  | } | 
|  | } | 
|  |  | 
|  | /// Create an OpenCL kernel for an enqueued block. | 
|  | /// | 
|  | /// The kernel has the same function type as the block invoke function. Its | 
|  | /// name is the name of the block invoke function postfixed with "_kernel". | 
|  | /// It simply calls the block invoke function then returns. | 
|  | llvm::Value *TargetCodeGenInfo::createEnqueuedBlockKernel( | 
|  | CodeGenFunction &CGF, llvm::Function *Invoke, llvm::Type *BlockTy) const { | 
|  | auto *InvokeFT = Invoke->getFunctionType(); | 
|  | auto &C = CGF.getLLVMContext(); | 
|  | std::string Name = Invoke->getName().str() + "_kernel"; | 
|  | auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C), | 
|  | InvokeFT->params(), false); | 
|  | auto *F = llvm::Function::Create(FT, llvm::GlobalValue::ExternalLinkage, Name, | 
|  | &CGF.CGM.getModule()); | 
|  | llvm::CallingConv::ID KernelCC = | 
|  | CGF.getTypes().ClangCallConvToLLVMCallConv(CallingConv::CC_DeviceKernel); | 
|  | F->setCallingConv(KernelCC); | 
|  |  | 
|  | llvm::AttrBuilder KernelAttrs(C); | 
|  |  | 
|  | // FIXME: This is missing setTargetAttributes | 
|  | CGF.CGM.addDefaultFunctionDefinitionAttributes(KernelAttrs); | 
|  | F->addFnAttrs(KernelAttrs); | 
|  |  | 
|  | auto IP = CGF.Builder.saveIP(); | 
|  | auto *BB = llvm::BasicBlock::Create(C, "entry", F); | 
|  | auto &Builder = CGF.Builder; | 
|  | Builder.SetInsertPoint(BB); | 
|  | llvm::SmallVector<llvm::Value *, 2> Args(llvm::make_pointer_range(F->args())); | 
|  | llvm::CallInst *Call = Builder.CreateCall(Invoke, Args); | 
|  | Call->setCallingConv(Invoke->getCallingConv()); | 
|  |  | 
|  | Builder.CreateRetVoid(); | 
|  | Builder.restoreIP(IP); | 
|  | return F; | 
|  | } | 
|  |  | 
|  | void TargetCodeGenInfo::setBranchProtectionFnAttributes( | 
|  | const TargetInfo::BranchProtectionInfo &BPI, llvm::Function &F) { | 
|  | // Called on already created and initialized function where attributes already | 
|  | // set from command line attributes but some might need to be removed as the | 
|  | // actual BPI is different. | 
|  | if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) { | 
|  | F.addFnAttr("sign-return-address", BPI.getSignReturnAddrStr()); | 
|  | F.addFnAttr("sign-return-address-key", BPI.getSignKeyStr()); | 
|  | } else { | 
|  | if (F.hasFnAttribute("sign-return-address")) | 
|  | F.removeFnAttr("sign-return-address"); | 
|  | if (F.hasFnAttribute("sign-return-address-key")) | 
|  | F.removeFnAttr("sign-return-address-key"); | 
|  | } | 
|  |  | 
|  | auto AddRemoveAttributeAsSet = [&](bool Set, const StringRef &ModAttr) { | 
|  | if (Set) | 
|  | F.addFnAttr(ModAttr); | 
|  | else if (F.hasFnAttribute(ModAttr)) | 
|  | F.removeFnAttr(ModAttr); | 
|  | }; | 
|  |  | 
|  | AddRemoveAttributeAsSet(BPI.BranchTargetEnforcement, | 
|  | "branch-target-enforcement"); | 
|  | AddRemoveAttributeAsSet(BPI.BranchProtectionPAuthLR, | 
|  | "branch-protection-pauth-lr"); | 
|  | AddRemoveAttributeAsSet(BPI.GuardedControlStack, "guarded-control-stack"); | 
|  | } | 
|  |  | 
|  | void TargetCodeGenInfo::initBranchProtectionFnAttributes( | 
|  | const TargetInfo::BranchProtectionInfo &BPI, llvm::AttrBuilder &FuncAttrs) { | 
|  | // Only used for initializing attributes in the AttrBuilder, which will not | 
|  | // contain any of these attributes so no need to remove anything. | 
|  | if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) { | 
|  | FuncAttrs.addAttribute("sign-return-address", BPI.getSignReturnAddrStr()); | 
|  | FuncAttrs.addAttribute("sign-return-address-key", BPI.getSignKeyStr()); | 
|  | } | 
|  | if (BPI.BranchTargetEnforcement) | 
|  | FuncAttrs.addAttribute("branch-target-enforcement"); | 
|  | if (BPI.BranchProtectionPAuthLR) | 
|  | FuncAttrs.addAttribute("branch-protection-pauth-lr"); | 
|  | if (BPI.GuardedControlStack) | 
|  | FuncAttrs.addAttribute("guarded-control-stack"); | 
|  | } | 
|  |  | 
|  | void TargetCodeGenInfo::setPointerAuthFnAttributes( | 
|  | const PointerAuthOptions &Opts, llvm::Function &F) { | 
|  | auto UpdateAttr = [&F](bool AttrShouldExist, StringRef AttrName) { | 
|  | if (AttrShouldExist && !F.hasFnAttribute(AttrName)) | 
|  | F.addFnAttr(AttrName); | 
|  | if (!AttrShouldExist && F.hasFnAttribute(AttrName)) | 
|  | F.removeFnAttr(AttrName); | 
|  | }; | 
|  | UpdateAttr(Opts.ReturnAddresses, "ptrauth-returns"); | 
|  | UpdateAttr((bool)Opts.FunctionPointers, "ptrauth-calls"); | 
|  | UpdateAttr(Opts.AuthTraps, "ptrauth-auth-traps"); | 
|  | UpdateAttr(Opts.IndirectGotos, "ptrauth-indirect-gotos"); | 
|  | UpdateAttr(Opts.AArch64JumpTableHardening, "aarch64-jump-table-hardening"); | 
|  | } | 
|  |  | 
|  | void TargetCodeGenInfo::initPointerAuthFnAttributes( | 
|  | const PointerAuthOptions &Opts, llvm::AttrBuilder &FuncAttrs) { | 
|  | if (Opts.ReturnAddresses) | 
|  | FuncAttrs.addAttribute("ptrauth-returns"); | 
|  | if (Opts.FunctionPointers) | 
|  | FuncAttrs.addAttribute("ptrauth-calls"); | 
|  | if (Opts.AuthTraps) | 
|  | FuncAttrs.addAttribute("ptrauth-auth-traps"); | 
|  | if (Opts.IndirectGotos) | 
|  | FuncAttrs.addAttribute("ptrauth-indirect-gotos"); | 
|  | if (Opts.AArch64JumpTableHardening) | 
|  | FuncAttrs.addAttribute("aarch64-jump-table-hardening"); | 
|  | } | 
|  |  | 
|  | namespace { | 
|  | class DefaultTargetCodeGenInfo : public TargetCodeGenInfo { | 
|  | public: | 
|  | DefaultTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) | 
|  | : TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {} | 
|  | }; | 
|  | } // namespace | 
|  |  | 
|  | std::unique_ptr<TargetCodeGenInfo> | 
|  | CodeGen::createDefaultTargetCodeGenInfo(CodeGenModule &CGM) { | 
|  | return std::make_unique<DefaultTargetCodeGenInfo>(CGM.getTypes()); | 
|  | } |