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