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