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
26using namespace clang;
27using namespace CodeGen;
28
29LLVM_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
70TargetCodeGenInfo::TargetCodeGenInfo(std::unique_ptr<ABIInfo> Info)
71 : Info(std::move(Info)) {}
72
73TargetCodeGenInfo::~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.
77unsigned 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
87bool 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
96void
97TargetCodeGenInfo::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
106unsigned 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
120void TargetCodeGenInfo::setOCLKernelStubCallingConvention(
121 const FunctionType *&FT) const {
122 FT = getABIInfo().getContext().adjustFunctionType(
123 Fn: FT, EInfo: FT->getExtInfo().withCallingConv(cc: CC_C));
124}
125
126llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM,
127 llvm::PointerType *T, QualType QT) const {
128 return llvm::ConstantPointerNull::get(T);
129}
130
131LangAS 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
139llvm::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
151llvm::Constant *
152TargetCodeGenInfo::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
160llvm::SyncScope::ID
161TargetCodeGenInfo::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
168void 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.
184llvm::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
216void 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
245void 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
261void 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
276void 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
290namespace {
291class DefaultTargetCodeGenInfo : public TargetCodeGenInfo {
292public:
293 DefaultTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
294 : TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(args&: CGT)) {}
295};
296} // namespace
297
298std::unique_ptr<TargetCodeGenInfo>
299CodeGen::createDefaultTargetCodeGenInfo(CodeGenModule &CGM) {
300 return std::make_unique<DefaultTargetCodeGenInfo>(args&: CGM.getTypes());
301}
302

source code of clang/lib/CodeGen/TargetInfo.cpp