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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // These classes wrap the information about a call or function 10 // 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 26 using namespace clang; 27 using namespace CodeGen; 28 29 LLVM_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 else 38 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 } 67 OS << ")\n"; 68 } 69 70 TargetCodeGenInfo::TargetCodeGenInfo(std::unique_ptr<ABIInfo> Info) 71 : Info(std::move(Info)) {} 72 73 TargetCodeGenInfo::~TargetCodeGenInfo() = default; 74 75 // If someone can figure out a general rule for this, that would be great. 76 // It's probably just doomed to be platform-dependent, though. 77 unsigned TargetCodeGenInfo::getSizeOfUnwindException() const { 78 // Verified for: 79 // x86-64 FreeBSD, Linux, Darwin 80 // x86-32 FreeBSD, Linux, Darwin 81 // PowerPC Linux 82 // ARM Darwin (*not* EABI) 83 // AArch64 Linux 84 return 32; 85 } 86 87 bool TargetCodeGenInfo::isNoProtoCallVariadic(const CallArgList &args, 88 const FunctionNoProtoType *fnType) const { 89 // The following conventions are known to require this to be false: 90 // x86_stdcall 91 // MIPS 92 // For everything else, we just prefer false unless we opt out. 93 return false; 94 } 95 96 void 97 TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib, 98 llvm::SmallString<24> &Opt) const { 99 // This assumes the user is passing a library name like "rt" instead of a 100 // filename like "librt.a/so", and that they don't care whether it's static or 101 // dynamic. 102 Opt = "-l"; 103 Opt += Lib; 104 } 105 106 unsigned TargetCodeGenInfo::getDeviceKernelCallingConv() const { 107 if (getABIInfo().getContext().getLangOpts().OpenCL) { 108 // Device kernels are called via an explicit runtime API with arguments, 109 // such as set with clSetKernelArg() for OpenCL, not as normal 110 // sub-functions. Return SPIR_KERNEL by default as the kernel calling 111 // convention to ensure the fingerprint is fixed such way that each kernel 112 // argument gets one matching argument in the produced kernel function 113 // argument list to enable feasible implementation of clSetKernelArg() with 114 // aggregates etc. In case we would use the default C calling conv here, 115 // clSetKernelArg() might break depending on the target-specific 116 // conventions; different targets might split structs passed as values 117 // to multiple function arguments etc. 118 return llvm::CallingConv::SPIR_KERNEL; 119 } 120 llvm_unreachable("Unknown kernel calling convention"); 121 } 122 123 void TargetCodeGenInfo::setOCLKernelStubCallingConvention( 124 const FunctionType *&FT) const { 125 FT = getABIInfo().getContext().adjustFunctionType( 126 FT, FT->getExtInfo().withCallingConv(CC_C)); 127 } 128 129 llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM, 130 llvm::PointerType *T, QualType QT) const { 131 return llvm::ConstantPointerNull::get(T); 132 } 133 134 LangAS TargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM, 135 const VarDecl *D) const { 136 assert(!CGM.getLangOpts().OpenCL && 137 !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) && 138 "Address space agnostic languages only"); 139 return D ? D->getType().getAddressSpace() : LangAS::Default; 140 } 141 142 llvm::Value *TargetCodeGenInfo::performAddrSpaceCast( 143 CodeGen::CodeGenFunction &CGF, llvm::Value *Src, LangAS SrcAddr, 144 llvm::Type *DestTy, bool isNonNull) const { 145 // Since target may map different address spaces in AST to the same address 146 // space, an address space conversion may end up as a bitcast. 147 if (auto *C = dyn_cast<llvm::Constant>(Src)) 148 return performAddrSpaceCast(CGF.CGM, C, SrcAddr, DestTy); 149 // Try to preserve the source's name to make IR more readable. 150 return CGF.Builder.CreateAddrSpaceCast( 151 Src, DestTy, Src->hasName() ? Src->getName() + ".ascast" : ""); 152 } 153 154 llvm::Constant * 155 TargetCodeGenInfo::performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *Src, 156 LangAS SrcAddr, 157 llvm::Type *DestTy) const { 158 // Since target may map different address spaces in AST to the same address 159 // space, an address space conversion may end up as a bitcast. 160 return llvm::ConstantExpr::getPointerCast(Src, DestTy); 161 } 162 163 llvm::SyncScope::ID 164 TargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &LangOpts, 165 SyncScope Scope, 166 llvm::AtomicOrdering Ordering, 167 llvm::LLVMContext &Ctx) const { 168 return Ctx.getOrInsertSyncScopeID(""); /* default sync scope */ 169 } 170 171 void TargetCodeGenInfo::addStackProbeTargetAttributes( 172 const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const { 173 if (llvm::Function *Fn = dyn_cast_or_null<llvm::Function>(GV)) { 174 if (CGM.getCodeGenOpts().StackProbeSize != 4096) 175 Fn->addFnAttr("stack-probe-size", 176 llvm::utostr(CGM.getCodeGenOpts().StackProbeSize)); 177 if (CGM.getCodeGenOpts().NoStackArgProbe) 178 Fn->addFnAttr("no-stack-arg-probe"); 179 } 180 } 181 182 /// Create an OpenCL kernel for an enqueued block. 183 /// 184 /// The kernel has the same function type as the block invoke function. Its 185 /// name is the name of the block invoke function postfixed with "_kernel". 186 /// It simply calls the block invoke function then returns. 187 llvm::Value *TargetCodeGenInfo::createEnqueuedBlockKernel( 188 CodeGenFunction &CGF, llvm::Function *Invoke, llvm::Type *BlockTy) const { 189 auto *InvokeFT = Invoke->getFunctionType(); 190 auto &C = CGF.getLLVMContext(); 191 std::string Name = Invoke->getName().str() + "_kernel"; 192 auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C), 193 InvokeFT->params(), false); 194 auto *F = llvm::Function::Create(FT, llvm::GlobalValue::ExternalLinkage, Name, 195 &CGF.CGM.getModule()); 196 llvm::CallingConv::ID KernelCC = 197 CGF.getTypes().ClangCallConvToLLVMCallConv(CallingConv::CC_DeviceKernel); 198 F->setCallingConv(KernelCC); 199 200 llvm::AttrBuilder KernelAttrs(C); 201 202 // FIXME: This is missing setTargetAttributes 203 CGF.CGM.addDefaultFunctionDefinitionAttributes(KernelAttrs); 204 F->addFnAttrs(KernelAttrs); 205 206 auto IP = CGF.Builder.saveIP(); 207 auto *BB = llvm::BasicBlock::Create(C, "entry", F); 208 auto &Builder = CGF.Builder; 209 Builder.SetInsertPoint(BB); 210 llvm::SmallVector<llvm::Value *, 2> Args(llvm::make_pointer_range(F->args())); 211 llvm::CallInst *Call = Builder.CreateCall(Invoke, Args); 212 Call->setCallingConv(Invoke->getCallingConv()); 213 214 Builder.CreateRetVoid(); 215 Builder.restoreIP(IP); 216 return F; 217 } 218 219 void TargetCodeGenInfo::setBranchProtectionFnAttributes( 220 const TargetInfo::BranchProtectionInfo &BPI, llvm::Function &F) { 221 // Called on already created and initialized function where attributes already 222 // set from command line attributes but some might need to be removed as the 223 // actual BPI is different. 224 if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) { 225 F.addFnAttr("sign-return-address", BPI.getSignReturnAddrStr()); 226 F.addFnAttr("sign-return-address-key", BPI.getSignKeyStr()); 227 } else { 228 if (F.hasFnAttribute("sign-return-address")) 229 F.removeFnAttr("sign-return-address"); 230 if (F.hasFnAttribute("sign-return-address-key")) 231 F.removeFnAttr("sign-return-address-key"); 232 } 233 234 auto AddRemoveAttributeAsSet = [&](bool Set, const StringRef &ModAttr) { 235 if (Set) 236 F.addFnAttr(ModAttr); 237 else if (F.hasFnAttribute(ModAttr)) 238 F.removeFnAttr(ModAttr); 239 }; 240 241 AddRemoveAttributeAsSet(BPI.BranchTargetEnforcement, 242 "branch-target-enforcement"); 243 AddRemoveAttributeAsSet(BPI.BranchProtectionPAuthLR, 244 "branch-protection-pauth-lr"); 245 AddRemoveAttributeAsSet(BPI.GuardedControlStack, "guarded-control-stack"); 246 } 247 248 void TargetCodeGenInfo::initBranchProtectionFnAttributes( 249 const TargetInfo::BranchProtectionInfo &BPI, llvm::AttrBuilder &FuncAttrs) { 250 // Only used for initializing attributes in the AttrBuilder, which will not 251 // contain any of these attributes so no need to remove anything. 252 if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) { 253 FuncAttrs.addAttribute("sign-return-address", BPI.getSignReturnAddrStr()); 254 FuncAttrs.addAttribute("sign-return-address-key", BPI.getSignKeyStr()); 255 } 256 if (BPI.BranchTargetEnforcement) 257 FuncAttrs.addAttribute("branch-target-enforcement"); 258 if (BPI.BranchProtectionPAuthLR) 259 FuncAttrs.addAttribute("branch-protection-pauth-lr"); 260 if (BPI.GuardedControlStack) 261 FuncAttrs.addAttribute("guarded-control-stack"); 262 } 263 264 void TargetCodeGenInfo::setPointerAuthFnAttributes( 265 const PointerAuthOptions &Opts, llvm::Function &F) { 266 auto UpdateAttr = [&F](bool AttrShouldExist, StringRef AttrName) { 267 if (AttrShouldExist && !F.hasFnAttribute(AttrName)) 268 F.addFnAttr(AttrName); 269 if (!AttrShouldExist && F.hasFnAttribute(AttrName)) 270 F.removeFnAttr(AttrName); 271 }; 272 UpdateAttr(Opts.ReturnAddresses, "ptrauth-returns"); 273 UpdateAttr((bool)Opts.FunctionPointers, "ptrauth-calls"); 274 UpdateAttr(Opts.AuthTraps, "ptrauth-auth-traps"); 275 UpdateAttr(Opts.IndirectGotos, "ptrauth-indirect-gotos"); 276 UpdateAttr(Opts.AArch64JumpTableHardening, "aarch64-jump-table-hardening"); 277 } 278 279 void TargetCodeGenInfo::initPointerAuthFnAttributes( 280 const PointerAuthOptions &Opts, llvm::AttrBuilder &FuncAttrs) { 281 if (Opts.ReturnAddresses) 282 FuncAttrs.addAttribute("ptrauth-returns"); 283 if (Opts.FunctionPointers) 284 FuncAttrs.addAttribute("ptrauth-calls"); 285 if (Opts.AuthTraps) 286 FuncAttrs.addAttribute("ptrauth-auth-traps"); 287 if (Opts.IndirectGotos) 288 FuncAttrs.addAttribute("ptrauth-indirect-gotos"); 289 if (Opts.AArch64JumpTableHardening) 290 FuncAttrs.addAttribute("aarch64-jump-table-hardening"); 291 } 292 293 namespace { 294 class DefaultTargetCodeGenInfo : public TargetCodeGenInfo { 295 public: 296 DefaultTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) 297 : TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {} 298 }; 299 } // namespace 300 301 std::unique_ptr<TargetCodeGenInfo> 302 CodeGen::createDefaultTargetCodeGenInfo(CodeGenModule &CGM) { 303 return std::make_unique<DefaultTargetCodeGenInfo>(CGM.getTypes()); 304 } 305