brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.9 KiB · 342a3af Raw
314 lines · cpp
1//===---- TargetInfo.cpp - Encapsulate target details -----------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// These classes wrap the information about a call or function10// definition used to handle ABI compliancy.11//12//===----------------------------------------------------------------------===//13 14#include "TargetInfo.h"15#include "ABIInfo.h"16#include "ABIInfoImpl.h"17#include "CodeGenFunction.h"18#include "clang/Basic/CodeGenOptions.h"19#include "clang/CodeGen/CGFunctionInfo.h"20#include "llvm/ADT/StringExtras.h"21#include "llvm/ADT/Twine.h"22#include "llvm/IR/Function.h"23#include "llvm/IR/Type.h"24#include "llvm/Support/raw_ostream.h"25 26using namespace clang;27using namespace CodeGen;28 29LLVM_DUMP_METHOD void ABIArgInfo::dump() const {30  raw_ostream &OS = llvm::errs();31  OS << "(ABIArgInfo Kind=";32  switch (TheKind) {33  case Direct:34    OS << "Direct Type=";35    if (llvm::Type *Ty = getCoerceToType())36      Ty->print(OS);37    else38      OS << "null";39    break;40  case Extend:41    OS << "Extend";42    break;43  case Ignore:44    OS << "Ignore";45    break;46  case InAlloca:47    OS << "InAlloca Offset=" << getInAllocaFieldIndex();48    break;49  case Indirect:50    OS << "Indirect Align=" << getIndirectAlign().getQuantity()51       << " ByVal=" << getIndirectByVal()52       << " Realign=" << getIndirectRealign();53    break;54  case IndirectAliased:55    OS << "Indirect Align=" << getIndirectAlign().getQuantity()56       << " AadrSpace=" << getIndirectAddrSpace()57       << " Realign=" << getIndirectRealign();58    break;59  case Expand:60    OS << "Expand";61    break;62  case CoerceAndExpand:63    OS << "CoerceAndExpand Type=";64    getCoerceAndExpandType()->print(OS);65    break;66  case TargetSpecific:67    OS << "TargetSpecific Type=";68    if (llvm::Type *Ty = getCoerceToType())69      Ty->print(OS);70    else71      OS << "null";72    break;73  }74  OS << ")\n";75}76 77TargetCodeGenInfo::TargetCodeGenInfo(std::unique_ptr<ABIInfo> Info)78    : Info(std::move(Info)) {}79 80TargetCodeGenInfo::~TargetCodeGenInfo() = default;81 82// If someone can figure out a general rule for this, that would be great.83// It's probably just doomed to be platform-dependent, though.84unsigned TargetCodeGenInfo::getSizeOfUnwindException() const {85  if (getABIInfo().getCodeGenOpts().hasSEHExceptions())86    return getABIInfo().getDataLayout().getPointerSizeInBits() > 32 ? 64 : 48;87  // Verified for:88  //   x86-64     FreeBSD, Linux, Darwin89  //   x86-32     FreeBSD, Linux, Darwin90  //   PowerPC    Linux91  //   ARM        Darwin (*not* EABI)92  //   AArch64    Linux93  return 32;94}95 96bool TargetCodeGenInfo::isNoProtoCallVariadic(const CallArgList &args,97                                     const FunctionNoProtoType *fnType) const {98  // The following conventions are known to require this to be false:99  //   x86_stdcall100  //   MIPS101  // For everything else, we just prefer false unless we opt out.102  return false;103}104 105void106TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib,107                                             llvm::SmallString<24> &Opt) const {108  // This assumes the user is passing a library name like "rt" instead of a109  // filename like "librt.a/so", and that they don't care whether it's static or110  // dynamic.111  Opt = "-l";112  Opt += Lib;113}114 115unsigned TargetCodeGenInfo::getDeviceKernelCallingConv() const {116  if (getABIInfo().getContext().getLangOpts().OpenCL) {117    // Device kernels are called via an explicit runtime API with arguments,118    // such as set with clSetKernelArg() for OpenCL, not as normal119    // sub-functions. Return SPIR_KERNEL by default as the kernel calling120    // convention to ensure the fingerprint is fixed such way that each kernel121    // argument gets one matching argument in the produced kernel function122    // argument list to enable feasible implementation of clSetKernelArg() with123    // aggregates etc. In case we would use the default C calling conv here,124    // clSetKernelArg() might break depending on the target-specific125    // conventions; different targets might split structs passed as values126    // to multiple function arguments etc.127    return llvm::CallingConv::SPIR_KERNEL;128  }129  llvm_unreachable("Unknown kernel calling convention");130}131 132void TargetCodeGenInfo::setOCLKernelStubCallingConvention(133    const FunctionType *&FT) const {134  FT = getABIInfo().getContext().adjustFunctionType(135      FT, FT->getExtInfo().withCallingConv(CC_C));136}137 138llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM,139    llvm::PointerType *T, QualType QT) const {140  return llvm::ConstantPointerNull::get(T);141}142 143LangAS TargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,144                                                   const VarDecl *D) const {145  assert(!CGM.getLangOpts().OpenCL &&146         !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&147         "Address space agnostic languages only");148  return D ? D->getType().getAddressSpace() : LangAS::Default;149}150 151llvm::Value *TargetCodeGenInfo::performAddrSpaceCast(152    CodeGen::CodeGenFunction &CGF, llvm::Value *Src, LangAS SrcAddr,153    llvm::Type *DestTy, bool isNonNull) const {154  // Since target may map different address spaces in AST to the same address155  // space, an address space conversion may end up as a bitcast.156  if (auto *C = dyn_cast<llvm::Constant>(Src))157    return performAddrSpaceCast(CGF.CGM, C, SrcAddr, DestTy);158  // Try to preserve the source's name to make IR more readable.159  return CGF.Builder.CreateAddrSpaceCast(160      Src, DestTy, Src->hasName() ? Src->getName() + ".ascast" : "");161}162 163llvm::Constant *164TargetCodeGenInfo::performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *Src,165                                        LangAS SrcAddr,166                                        llvm::Type *DestTy) const {167  // Since target may map different address spaces in AST to the same address168  // space, an address space conversion may end up as a bitcast.169  return llvm::ConstantExpr::getPointerCast(Src, DestTy);170}171 172llvm::SyncScope::ID173TargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &LangOpts,174                                      SyncScope Scope,175                                      llvm::AtomicOrdering Ordering,176                                      llvm::LLVMContext &Ctx) const {177  return Ctx.getOrInsertSyncScopeID(""); /* default sync scope */178}179 180void TargetCodeGenInfo::addStackProbeTargetAttributes(181    const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const {182  if (llvm::Function *Fn = dyn_cast_or_null<llvm::Function>(GV)) {183    if (CGM.getCodeGenOpts().StackProbeSize != 4096)184      Fn->addFnAttr("stack-probe-size",185                    llvm::utostr(CGM.getCodeGenOpts().StackProbeSize));186    if (CGM.getCodeGenOpts().NoStackArgProbe)187      Fn->addFnAttr("no-stack-arg-probe");188  }189}190 191/// Create an OpenCL kernel for an enqueued block.192///193/// The kernel has the same function type as the block invoke function. Its194/// name is the name of the block invoke function postfixed with "_kernel".195/// It simply calls the block invoke function then returns.196llvm::Value *TargetCodeGenInfo::createEnqueuedBlockKernel(197    CodeGenFunction &CGF, llvm::Function *Invoke, llvm::Type *BlockTy) const {198  auto *InvokeFT = Invoke->getFunctionType();199  auto &C = CGF.getLLVMContext();200  std::string Name = Invoke->getName().str() + "_kernel";201  auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C),202                                     InvokeFT->params(), false);203  auto *F = llvm::Function::Create(FT, llvm::GlobalValue::ExternalLinkage, Name,204                                   &CGF.CGM.getModule());205  llvm::CallingConv::ID KernelCC =206      CGF.getTypes().ClangCallConvToLLVMCallConv(CallingConv::CC_DeviceKernel);207  F->setCallingConv(KernelCC);208 209  llvm::AttrBuilder KernelAttrs(C);210 211  // FIXME: This is missing setTargetAttributes212  CGF.CGM.addDefaultFunctionDefinitionAttributes(KernelAttrs);213  F->addFnAttrs(KernelAttrs);214 215  auto IP = CGF.Builder.saveIP();216  auto *BB = llvm::BasicBlock::Create(C, "entry", F);217  auto &Builder = CGF.Builder;218  Builder.SetInsertPoint(BB);219  llvm::SmallVector<llvm::Value *, 2> Args(llvm::make_pointer_range(F->args()));220  llvm::CallInst *Call = Builder.CreateCall(Invoke, Args);221  Call->setCallingConv(Invoke->getCallingConv());222 223  Builder.CreateRetVoid();224  Builder.restoreIP(IP);225  return F;226}227 228void TargetCodeGenInfo::setBranchProtectionFnAttributes(229    const TargetInfo::BranchProtectionInfo &BPI, llvm::Function &F) {230  // Called on already created and initialized function where attributes already231  // set from command line attributes but some might need to be removed as the232  // actual BPI is different.233  if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {234    F.addFnAttr("sign-return-address", BPI.getSignReturnAddrStr());235    F.addFnAttr("sign-return-address-key", BPI.getSignKeyStr());236  } else {237    if (F.hasFnAttribute("sign-return-address"))238      F.removeFnAttr("sign-return-address");239    if (F.hasFnAttribute("sign-return-address-key"))240      F.removeFnAttr("sign-return-address-key");241  }242 243  auto AddRemoveAttributeAsSet = [&](bool Set, const StringRef &ModAttr) {244    if (Set)245      F.addFnAttr(ModAttr);246    else if (F.hasFnAttribute(ModAttr))247      F.removeFnAttr(ModAttr);248  };249 250  AddRemoveAttributeAsSet(BPI.BranchTargetEnforcement,251                          "branch-target-enforcement");252  AddRemoveAttributeAsSet(BPI.BranchProtectionPAuthLR,253                          "branch-protection-pauth-lr");254  AddRemoveAttributeAsSet(BPI.GuardedControlStack, "guarded-control-stack");255}256 257void TargetCodeGenInfo::initBranchProtectionFnAttributes(258    const TargetInfo::BranchProtectionInfo &BPI, llvm::AttrBuilder &FuncAttrs) {259  // Only used for initializing attributes in the AttrBuilder, which will not260  // contain any of these attributes so no need to remove anything.261  if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {262    FuncAttrs.addAttribute("sign-return-address", BPI.getSignReturnAddrStr());263    FuncAttrs.addAttribute("sign-return-address-key", BPI.getSignKeyStr());264  }265  if (BPI.BranchTargetEnforcement)266    FuncAttrs.addAttribute("branch-target-enforcement");267  if (BPI.BranchProtectionPAuthLR)268    FuncAttrs.addAttribute("branch-protection-pauth-lr");269  if (BPI.GuardedControlStack)270    FuncAttrs.addAttribute("guarded-control-stack");271}272 273void TargetCodeGenInfo::setPointerAuthFnAttributes(274    const PointerAuthOptions &Opts, llvm::Function &F) {275  auto UpdateAttr = [&F](bool AttrShouldExist, StringRef AttrName) {276    if (AttrShouldExist && !F.hasFnAttribute(AttrName))277      F.addFnAttr(AttrName);278    if (!AttrShouldExist && F.hasFnAttribute(AttrName))279      F.removeFnAttr(AttrName);280  };281  UpdateAttr(Opts.ReturnAddresses, "ptrauth-returns");282  UpdateAttr((bool)Opts.FunctionPointers, "ptrauth-calls");283  UpdateAttr(Opts.AuthTraps, "ptrauth-auth-traps");284  UpdateAttr(Opts.IndirectGotos, "ptrauth-indirect-gotos");285  UpdateAttr(Opts.AArch64JumpTableHardening, "aarch64-jump-table-hardening");286}287 288void TargetCodeGenInfo::initPointerAuthFnAttributes(289    const PointerAuthOptions &Opts, llvm::AttrBuilder &FuncAttrs) {290  if (Opts.ReturnAddresses)291    FuncAttrs.addAttribute("ptrauth-returns");292  if (Opts.FunctionPointers)293    FuncAttrs.addAttribute("ptrauth-calls");294  if (Opts.AuthTraps)295    FuncAttrs.addAttribute("ptrauth-auth-traps");296  if (Opts.IndirectGotos)297    FuncAttrs.addAttribute("ptrauth-indirect-gotos");298  if (Opts.AArch64JumpTableHardening)299    FuncAttrs.addAttribute("aarch64-jump-table-hardening");300}301 302namespace {303class DefaultTargetCodeGenInfo : public TargetCodeGenInfo {304public:305  DefaultTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)306      : TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {}307};308} // namespace309 310std::unique_ptr<TargetCodeGenInfo>311CodeGen::createDefaultTargetCodeGenInfo(CodeGenModule &CGM) {312  return std::make_unique<DefaultTargetCodeGenInfo>(CGM.getTypes());313}314