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
dump() const29 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
TargetCodeGenInfo(std::unique_ptr<ABIInfo> Info)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.
getSizeOfUnwindException() const77 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
isNoProtoCallVariadic(const CallArgList & args,const FunctionNoProtoType * fnType) const89 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
getDependentLibraryOption(llvm::StringRef Lib,llvm::SmallString<24> & Opt) const99 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
getDeviceKernelCallingConv() const108 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
setOCLKernelStubCallingConvention(const FunctionType * & FT) const125 void TargetCodeGenInfo::setOCLKernelStubCallingConvention(
126 const FunctionType *&FT) const {
127 FT = getABIInfo().getContext().adjustFunctionType(
128 FT, FT->getExtInfo().withCallingConv(CC_C));
129 }
130
getNullPointer(const CodeGen::CodeGenModule & CGM,llvm::PointerType * T,QualType QT) const131 llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM,
132 llvm::PointerType *T, QualType QT) const {
133 return llvm::ConstantPointerNull::get(T);
134 }
135
getGlobalVarAddressSpace(CodeGenModule & CGM,const VarDecl * D) const136 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
performAddrSpaceCast(CodeGen::CodeGenFunction & CGF,llvm::Value * Src,LangAS SrcAddr,llvm::Type * DestTy,bool isNonNull) const144 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 *
performAddrSpaceCast(CodeGenModule & CGM,llvm::Constant * Src,LangAS SrcAddr,llvm::Type * DestTy) const157 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
getLLVMSyncScopeID(const LangOptions & LangOpts,SyncScope Scope,llvm::AtomicOrdering Ordering,llvm::LLVMContext & Ctx) const166 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
addStackProbeTargetAttributes(const Decl * D,llvm::GlobalValue * GV,CodeGen::CodeGenModule & CGM) const173 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.
createEnqueuedBlockKernel(CodeGenFunction & CGF,llvm::Function * Invoke,llvm::Type * BlockTy) const189 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
setBranchProtectionFnAttributes(const TargetInfo::BranchProtectionInfo & BPI,llvm::Function & F)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
initBranchProtectionFnAttributes(const TargetInfo::BranchProtectionInfo & BPI,llvm::AttrBuilder & FuncAttrs)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
setPointerAuthFnAttributes(const PointerAuthOptions & Opts,llvm::Function & F)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
initPointerAuthFnAttributes(const PointerAuthOptions & Opts,llvm::AttrBuilder & FuncAttrs)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:
DefaultTargetCodeGenInfo(CodeGen::CodeGenTypes & CGT)298 DefaultTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
299 : TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {}
300 };
301 } // namespace
302
303 std::unique_ptr<TargetCodeGenInfo>
createDefaultTargetCodeGenInfo(CodeGenModule & CGM)304 CodeGen::createDefaultTargetCodeGenInfo(CodeGenModule &CGM) {
305 return std::make_unique<DefaultTargetCodeGenInfo>(CGM.getTypes());
306 }
307