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(O&: 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(O&: 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 | Fn: FT, EInfo: FT->getExtInfo().withCallingConv(cc: 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>(Val: Src)) |
148 | return performAddrSpaceCast(CGM&: CGF.CGM, V: C, SrcAddr, DestTy); |
149 | // Try to preserve the source's name to make IR more readable. |
150 | return CGF.Builder.CreateAddrSpaceCast( |
151 | V: Src, DestTy, Name: 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(C: Src, Ty: 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(SSN: "" ); /* 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>(Val: GV)) { |
174 | if (CGM.getCodeGenOpts().StackProbeSize != 4096) |
175 | Fn->addFnAttr(Kind: "stack-probe-size" , |
176 | Val: llvm::utostr(X: CGM.getCodeGenOpts().StackProbeSize)); |
177 | if (CGM.getCodeGenOpts().NoStackArgProbe) |
178 | Fn->addFnAttr(Kind: "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(Result: llvm::Type::getVoidTy(C), |
193 | Params: InvokeFT->params(), isVarArg: false); |
194 | auto *F = llvm::Function::Create(Ty: FT, Linkage: llvm::GlobalValue::ExternalLinkage, N: Name, |
195 | M: &CGF.CGM.getModule()); |
196 | llvm::CallingConv::ID KernelCC = |
197 | CGF.getTypes().ClangCallConvToLLVMCallConv(CC: CallingConv::CC_DeviceKernel); |
198 | F->setCallingConv(KernelCC); |
199 | |
200 | llvm::AttrBuilder KernelAttrs(C); |
201 | |
202 | // FIXME: This is missing setTargetAttributes |
203 | CGF.CGM.addDefaultFunctionDefinitionAttributes(attrs&: KernelAttrs); |
204 | F->addFnAttrs(Attrs: KernelAttrs); |
205 | |
206 | auto IP = CGF.Builder.saveIP(); |
207 | auto *BB = llvm::BasicBlock::Create(Context&: C, Name: "entry" , Parent: F); |
208 | auto &Builder = CGF.Builder; |
209 | Builder.SetInsertPoint(BB); |
210 | llvm::SmallVector<llvm::Value *, 2> Args(llvm::make_pointer_range(Range: F->args())); |
211 | llvm::CallInst *Call = Builder.CreateCall(Callee: 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(Kind: "sign-return-address" , Val: BPI.getSignReturnAddrStr()); |
226 | F.addFnAttr(Kind: "sign-return-address-key" , Val: BPI.getSignKeyStr()); |
227 | } else { |
228 | if (F.hasFnAttribute(Kind: "sign-return-address" )) |
229 | F.removeFnAttr(Kind: "sign-return-address" ); |
230 | if (F.hasFnAttribute(Kind: "sign-return-address-key" )) |
231 | F.removeFnAttr(Kind: "sign-return-address-key" ); |
232 | } |
233 | |
234 | auto AddRemoveAttributeAsSet = [&](bool Set, const StringRef &ModAttr) { |
235 | if (Set) |
236 | F.addFnAttr(Kind: ModAttr); |
237 | else if (F.hasFnAttribute(Kind: ModAttr)) |
238 | F.removeFnAttr(Kind: 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(A: "sign-return-address" , V: BPI.getSignReturnAddrStr()); |
254 | FuncAttrs.addAttribute(A: "sign-return-address-key" , V: BPI.getSignKeyStr()); |
255 | } |
256 | if (BPI.BranchTargetEnforcement) |
257 | FuncAttrs.addAttribute(A: "branch-target-enforcement" ); |
258 | if (BPI.BranchProtectionPAuthLR) |
259 | FuncAttrs.addAttribute(A: "branch-protection-pauth-lr" ); |
260 | if (BPI.GuardedControlStack) |
261 | FuncAttrs.addAttribute(A: "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(Kind: AttrName)) |
268 | F.addFnAttr(Kind: AttrName); |
269 | if (!AttrShouldExist && F.hasFnAttribute(Kind: AttrName)) |
270 | F.removeFnAttr(Kind: 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(A: "ptrauth-returns" ); |
283 | if (Opts.FunctionPointers) |
284 | FuncAttrs.addAttribute(A: "ptrauth-calls" ); |
285 | if (Opts.AuthTraps) |
286 | FuncAttrs.addAttribute(A: "ptrauth-auth-traps" ); |
287 | if (Opts.IndirectGotos) |
288 | FuncAttrs.addAttribute(A: "ptrauth-indirect-gotos" ); |
289 | if (Opts.AArch64JumpTableHardening) |
290 | FuncAttrs.addAttribute(A: "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>(args&: CGT)) {} |
298 | }; |
299 | } // namespace |
300 | |
301 | std::unique_ptr<TargetCodeGenInfo> |
302 | CodeGen::createDefaultTargetCodeGenInfo(CodeGenModule &CGM) { |
303 | return std::make_unique<DefaultTargetCodeGenInfo>(args&: CGM.getTypes()); |
304 | } |
305 | |