10b57cec5SDimitry Andric //===---- TargetInfo.cpp - Encapsulate target details -----------*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // These classes wrap the information about a call or function 100b57cec5SDimitry Andric // definition used to handle ABI compliancy. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "TargetInfo.h" 150b57cec5SDimitry Andric #include "ABIInfo.h" 1606c3fb27SDimitry Andric #include "ABIInfoImpl.h" 170b57cec5SDimitry Andric #include "CodeGenFunction.h" 180b57cec5SDimitry Andric #include "clang/Basic/CodeGenOptions.h" 190b57cec5SDimitry Andric #include "clang/CodeGen/CGFunctionInfo.h" 200b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h" 210b57cec5SDimitry Andric #include "llvm/ADT/Twine.h" 220fca6ea1SDimitry Andric #include "llvm/IR/Function.h" 230b57cec5SDimitry Andric #include "llvm/IR/Type.h" 240b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric using namespace clang; 270b57cec5SDimitry Andric using namespace CodeGen; 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric LLVM_DUMP_METHOD void ABIArgInfo::dump() const { 300b57cec5SDimitry Andric raw_ostream &OS = llvm::errs(); 310b57cec5SDimitry Andric OS << "(ABIArgInfo Kind="; 320b57cec5SDimitry Andric switch (TheKind) { 330b57cec5SDimitry Andric case Direct: 340b57cec5SDimitry Andric OS << "Direct Type="; 350b57cec5SDimitry Andric if (llvm::Type *Ty = getCoerceToType()) 360b57cec5SDimitry Andric Ty->print(OS); 370b57cec5SDimitry Andric else 380b57cec5SDimitry Andric OS << "null"; 390b57cec5SDimitry Andric break; 400b57cec5SDimitry Andric case Extend: 410b57cec5SDimitry Andric OS << "Extend"; 420b57cec5SDimitry Andric break; 430b57cec5SDimitry Andric case Ignore: 440b57cec5SDimitry Andric OS << "Ignore"; 450b57cec5SDimitry Andric break; 460b57cec5SDimitry Andric case InAlloca: 470b57cec5SDimitry Andric OS << "InAlloca Offset=" << getInAllocaFieldIndex(); 480b57cec5SDimitry Andric break; 490b57cec5SDimitry Andric case Indirect: 500b57cec5SDimitry Andric OS << "Indirect Align=" << getIndirectAlign().getQuantity() 510b57cec5SDimitry Andric << " ByVal=" << getIndirectByVal() 520b57cec5SDimitry Andric << " Realign=" << getIndirectRealign(); 530b57cec5SDimitry Andric break; 54e8d8bef9SDimitry Andric case IndirectAliased: 55e8d8bef9SDimitry Andric OS << "Indirect Align=" << getIndirectAlign().getQuantity() 56e8d8bef9SDimitry Andric << " AadrSpace=" << getIndirectAddrSpace() 57e8d8bef9SDimitry Andric << " Realign=" << getIndirectRealign(); 58e8d8bef9SDimitry Andric break; 590b57cec5SDimitry Andric case Expand: 600b57cec5SDimitry Andric OS << "Expand"; 610b57cec5SDimitry Andric break; 620b57cec5SDimitry Andric case CoerceAndExpand: 630b57cec5SDimitry Andric OS << "CoerceAndExpand Type="; 640b57cec5SDimitry Andric getCoerceAndExpandType()->print(OS); 650b57cec5SDimitry Andric break; 660b57cec5SDimitry Andric } 670b57cec5SDimitry Andric OS << ")\n"; 680b57cec5SDimitry Andric } 690b57cec5SDimitry Andric 70fcaf7f86SDimitry Andric TargetCodeGenInfo::TargetCodeGenInfo(std::unique_ptr<ABIInfo> Info) 71fcaf7f86SDimitry Andric : Info(std::move(Info)) {} 72fcaf7f86SDimitry Andric 735ffd83dbSDimitry Andric TargetCodeGenInfo::~TargetCodeGenInfo() = default; 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric // If someone can figure out a general rule for this, that would be great. 760b57cec5SDimitry Andric // It's probably just doomed to be platform-dependent, though. 770b57cec5SDimitry Andric unsigned TargetCodeGenInfo::getSizeOfUnwindException() const { 780b57cec5SDimitry Andric // Verified for: 790b57cec5SDimitry Andric // x86-64 FreeBSD, Linux, Darwin 800b57cec5SDimitry Andric // x86-32 FreeBSD, Linux, Darwin 8106c3fb27SDimitry Andric // PowerPC Linux 820b57cec5SDimitry Andric // ARM Darwin (*not* EABI) 830b57cec5SDimitry Andric // AArch64 Linux 840b57cec5SDimitry Andric return 32; 850b57cec5SDimitry Andric } 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric bool TargetCodeGenInfo::isNoProtoCallVariadic(const CallArgList &args, 880b57cec5SDimitry Andric const FunctionNoProtoType *fnType) const { 890b57cec5SDimitry Andric // The following conventions are known to require this to be false: 900b57cec5SDimitry Andric // x86_stdcall 910b57cec5SDimitry Andric // MIPS 920b57cec5SDimitry Andric // For everything else, we just prefer false unless we opt out. 930b57cec5SDimitry Andric return false; 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric void 970b57cec5SDimitry Andric TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib, 980b57cec5SDimitry Andric llvm::SmallString<24> &Opt) const { 990b57cec5SDimitry Andric // This assumes the user is passing a library name like "rt" instead of a 1000b57cec5SDimitry Andric // filename like "librt.a/so", and that they don't care whether it's static or 1010b57cec5SDimitry Andric // dynamic. 1020b57cec5SDimitry Andric Opt = "-l"; 1030b57cec5SDimitry Andric Opt += Lib; 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric unsigned TargetCodeGenInfo::getOpenCLKernelCallingConv() const { 1070b57cec5SDimitry Andric // OpenCL kernels are called via an explicit runtime API with arguments 1080b57cec5SDimitry Andric // set with clSetKernelArg(), not as normal sub-functions. 1090b57cec5SDimitry Andric // Return SPIR_KERNEL by default as the kernel calling convention to 1100b57cec5SDimitry Andric // ensure the fingerprint is fixed such way that each OpenCL argument 1110b57cec5SDimitry Andric // gets one matching argument in the produced kernel function argument 1120b57cec5SDimitry Andric // list to enable feasible implementation of clSetKernelArg() with 1130b57cec5SDimitry Andric // aggregates etc. In case we would use the default C calling conv here, 1140b57cec5SDimitry Andric // clSetKernelArg() might break depending on the target-specific 1150b57cec5SDimitry Andric // conventions; different targets might split structs passed as values 1160b57cec5SDimitry Andric // to multiple function arguments etc. 1170b57cec5SDimitry Andric return llvm::CallingConv::SPIR_KERNEL; 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM, 1210b57cec5SDimitry Andric llvm::PointerType *T, QualType QT) const { 1220b57cec5SDimitry Andric return llvm::ConstantPointerNull::get(T); 1230b57cec5SDimitry Andric } 1240b57cec5SDimitry Andric 1250b57cec5SDimitry Andric LangAS TargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM, 1260b57cec5SDimitry Andric const VarDecl *D) const { 1270b57cec5SDimitry Andric assert(!CGM.getLangOpts().OpenCL && 1280b57cec5SDimitry Andric !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) && 1290b57cec5SDimitry Andric "Address space agnostic languages only"); 1300b57cec5SDimitry Andric return D ? D->getType().getAddressSpace() : LangAS::Default; 1310b57cec5SDimitry Andric } 1320b57cec5SDimitry Andric 1330b57cec5SDimitry Andric llvm::Value *TargetCodeGenInfo::performAddrSpaceCast( 1340b57cec5SDimitry Andric CodeGen::CodeGenFunction &CGF, llvm::Value *Src, LangAS SrcAddr, 1350b57cec5SDimitry Andric LangAS DestAddr, llvm::Type *DestTy, bool isNonNull) const { 1360b57cec5SDimitry Andric // Since target may map different address spaces in AST to the same address 1370b57cec5SDimitry Andric // space, an address space conversion may end up as a bitcast. 1380b57cec5SDimitry Andric if (auto *C = dyn_cast<llvm::Constant>(Src)) 1390b57cec5SDimitry Andric return performAddrSpaceCast(CGF.CGM, C, SrcAddr, DestAddr, DestTy); 1400b57cec5SDimitry Andric // Try to preserve the source's name to make IR more readable. 1415f757f3fSDimitry Andric return CGF.Builder.CreateAddrSpaceCast( 1420b57cec5SDimitry Andric Src, DestTy, Src->hasName() ? Src->getName() + ".ascast" : ""); 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric llvm::Constant * 1460b57cec5SDimitry Andric TargetCodeGenInfo::performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *Src, 1470b57cec5SDimitry Andric LangAS SrcAddr, LangAS DestAddr, 1480b57cec5SDimitry Andric llvm::Type *DestTy) const { 1490b57cec5SDimitry Andric // Since target may map different address spaces in AST to the same address 1500b57cec5SDimitry Andric // space, an address space conversion may end up as a bitcast. 1510b57cec5SDimitry Andric return llvm::ConstantExpr::getPointerCast(Src, DestTy); 1520b57cec5SDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric llvm::SyncScope::ID 1550b57cec5SDimitry Andric TargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &LangOpts, 1560b57cec5SDimitry Andric SyncScope Scope, 1570b57cec5SDimitry Andric llvm::AtomicOrdering Ordering, 1580b57cec5SDimitry Andric llvm::LLVMContext &Ctx) const { 1590b57cec5SDimitry Andric return Ctx.getOrInsertSyncScopeID(""); /* default sync scope */ 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 16206c3fb27SDimitry Andric void TargetCodeGenInfo::addStackProbeTargetAttributes( 1630b57cec5SDimitry Andric const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { 1640b57cec5SDimitry Andric if (llvm::Function *Fn = dyn_cast_or_null<llvm::Function>(GV)) { 1650b57cec5SDimitry Andric if (CGM.getCodeGenOpts().StackProbeSize != 4096) 1660b57cec5SDimitry Andric Fn->addFnAttr("stack-probe-size", 1670b57cec5SDimitry Andric llvm::utostr(CGM.getCodeGenOpts().StackProbeSize)); 1680b57cec5SDimitry Andric if (CGM.getCodeGenOpts().NoStackArgProbe) 1690b57cec5SDimitry Andric Fn->addFnAttr("no-stack-arg-probe"); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric } 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric /// Create an OpenCL kernel for an enqueued block. 1740b57cec5SDimitry Andric /// 1750b57cec5SDimitry Andric /// The kernel has the same function type as the block invoke function. Its 1760b57cec5SDimitry Andric /// name is the name of the block invoke function postfixed with "_kernel". 1770b57cec5SDimitry Andric /// It simply calls the block invoke function then returns. 17806c3fb27SDimitry Andric llvm::Value *TargetCodeGenInfo::createEnqueuedBlockKernel( 17906c3fb27SDimitry Andric CodeGenFunction &CGF, llvm::Function *Invoke, llvm::Type *BlockTy) const { 1800b57cec5SDimitry Andric auto *InvokeFT = Invoke->getFunctionType(); 1810b57cec5SDimitry Andric auto &C = CGF.getLLVMContext(); 1820b57cec5SDimitry Andric std::string Name = Invoke->getName().str() + "_kernel"; 18381ad6265SDimitry Andric auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C), 18481ad6265SDimitry Andric InvokeFT->params(), false); 18504eeddc0SDimitry Andric auto *F = llvm::Function::Create(FT, llvm::GlobalValue::ExternalLinkage, Name, 1860b57cec5SDimitry Andric &CGF.CGM.getModule()); 18706c3fb27SDimitry Andric llvm::CallingConv::ID KernelCC = 18806c3fb27SDimitry Andric CGF.getTypes().ClangCallConvToLLVMCallConv(CallingConv::CC_OpenCLKernel); 18906c3fb27SDimitry Andric F->setCallingConv(KernelCC); 19006c3fb27SDimitry Andric 19106c3fb27SDimitry Andric llvm::AttrBuilder KernelAttrs(C); 19206c3fb27SDimitry Andric 19306c3fb27SDimitry Andric // FIXME: This is missing setTargetAttributes 19406c3fb27SDimitry Andric CGF.CGM.addDefaultFunctionDefinitionAttributes(KernelAttrs); 19506c3fb27SDimitry Andric F->addFnAttrs(KernelAttrs); 19606c3fb27SDimitry Andric 1970b57cec5SDimitry Andric auto IP = CGF.Builder.saveIP(); 1980b57cec5SDimitry Andric auto *BB = llvm::BasicBlock::Create(C, "entry", F); 1990b57cec5SDimitry Andric auto &Builder = CGF.Builder; 2000b57cec5SDimitry Andric Builder.SetInsertPoint(BB); 20181ad6265SDimitry Andric llvm::SmallVector<llvm::Value *, 2> Args(llvm::make_pointer_range(F->args())); 20206c3fb27SDimitry Andric llvm::CallInst *Call = Builder.CreateCall(Invoke, Args); 20306c3fb27SDimitry Andric Call->setCallingConv(Invoke->getCallingConv()); 20406c3fb27SDimitry Andric 2050b57cec5SDimitry Andric Builder.CreateRetVoid(); 2060b57cec5SDimitry Andric Builder.restoreIP(IP); 2070b57cec5SDimitry Andric return F; 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 2100fca6ea1SDimitry Andric void TargetCodeGenInfo::setBranchProtectionFnAttributes( 2110fca6ea1SDimitry Andric const TargetInfo::BranchProtectionInfo &BPI, llvm::Function &F) { 212*62987288SDimitry Andric // Called on already created and initialized function where attributes already 213*62987288SDimitry Andric // set from command line attributes but some might need to be removed as the 214*62987288SDimitry Andric // actual BPI is different. 215*62987288SDimitry Andric if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) { 216*62987288SDimitry Andric F.addFnAttr("sign-return-address", BPI.getSignReturnAddrStr()); 217*62987288SDimitry Andric F.addFnAttr("sign-return-address-key", BPI.getSignKeyStr()); 218*62987288SDimitry Andric } else { 219*62987288SDimitry Andric if (F.hasFnAttribute("sign-return-address")) 220*62987288SDimitry Andric F.removeFnAttr("sign-return-address"); 221*62987288SDimitry Andric if (F.hasFnAttribute("sign-return-address-key")) 222*62987288SDimitry Andric F.removeFnAttr("sign-return-address-key"); 2230fca6ea1SDimitry Andric } 2240fca6ea1SDimitry Andric 225*62987288SDimitry Andric auto AddRemoveAttributeAsSet = [&](bool Set, const StringRef &ModAttr) { 226*62987288SDimitry Andric if (Set) 227*62987288SDimitry Andric F.addFnAttr(ModAttr); 228*62987288SDimitry Andric else if (F.hasFnAttribute(ModAttr)) 229*62987288SDimitry Andric F.removeFnAttr(ModAttr); 230*62987288SDimitry Andric }; 231*62987288SDimitry Andric 232*62987288SDimitry Andric AddRemoveAttributeAsSet(BPI.BranchTargetEnforcement, 233*62987288SDimitry Andric "branch-target-enforcement"); 234*62987288SDimitry Andric AddRemoveAttributeAsSet(BPI.BranchProtectionPAuthLR, 235*62987288SDimitry Andric "branch-protection-pauth-lr"); 236*62987288SDimitry Andric AddRemoveAttributeAsSet(BPI.GuardedControlStack, "guarded-control-stack"); 237*62987288SDimitry Andric } 238*62987288SDimitry Andric 239*62987288SDimitry Andric void TargetCodeGenInfo::initBranchProtectionFnAttributes( 2400fca6ea1SDimitry Andric const TargetInfo::BranchProtectionInfo &BPI, llvm::AttrBuilder &FuncAttrs) { 241*62987288SDimitry Andric // Only used for initializing attributes in the AttrBuilder, which will not 242*62987288SDimitry Andric // contain any of these attributes so no need to remove anything. 2430fca6ea1SDimitry Andric if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) { 2440fca6ea1SDimitry Andric FuncAttrs.addAttribute("sign-return-address", BPI.getSignReturnAddrStr()); 2450fca6ea1SDimitry Andric FuncAttrs.addAttribute("sign-return-address-key", BPI.getSignKeyStr()); 2460fca6ea1SDimitry Andric } 2470fca6ea1SDimitry Andric if (BPI.BranchTargetEnforcement) 2480fca6ea1SDimitry Andric FuncAttrs.addAttribute("branch-target-enforcement"); 2490fca6ea1SDimitry Andric if (BPI.BranchProtectionPAuthLR) 2500fca6ea1SDimitry Andric FuncAttrs.addAttribute("branch-protection-pauth-lr"); 2510fca6ea1SDimitry Andric if (BPI.GuardedControlStack) 2520fca6ea1SDimitry Andric FuncAttrs.addAttribute("guarded-control-stack"); 2530fca6ea1SDimitry Andric } 2540fca6ea1SDimitry Andric 25506c3fb27SDimitry Andric namespace { 25606c3fb27SDimitry Andric class DefaultTargetCodeGenInfo : public TargetCodeGenInfo { 25706c3fb27SDimitry Andric public: 25806c3fb27SDimitry Andric DefaultTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) 25906c3fb27SDimitry Andric : TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {} 26006c3fb27SDimitry Andric }; 26106c3fb27SDimitry Andric } // namespace 2620b57cec5SDimitry Andric 26306c3fb27SDimitry Andric std::unique_ptr<TargetCodeGenInfo> 26406c3fb27SDimitry Andric CodeGen::createDefaultTargetCodeGenInfo(CodeGenModule &CGM) { 26506c3fb27SDimitry Andric return std::make_unique<DefaultTargetCodeGenInfo>(CGM.getTypes()); 2660b57cec5SDimitry Andric } 267