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 case TargetSpecific:
67 OS << "TargetSpecific Type=";
68 if (llvm::Type *Ty = getCoerceToType())
69 Ty->print(O&: OS);
70 else
71 OS << "null";
72 break;
73 }
74 OS << ")\n";
75}
76
77TargetCodeGenInfo::TargetCodeGenInfo(std::unique_ptr<ABIInfo> Info)
78 : Info(std::move(Info)) {}
79
80TargetCodeGenInfo::~TargetCodeGenInfo() = default;
81
82// If someone can figure out a general rule for this, that would be great.
83// It's probably just doomed to be platform-dependent, though.
84unsigned TargetCodeGenInfo::getSizeOfUnwindException() const {
85 if (getABIInfo().getCodeGenOpts().hasSEHExceptions())
86 return getABIInfo().getDataLayout().getPointerSizeInBits() > 32 ? 64 : 48;
87 // Verified for:
88 // x86-64 FreeBSD, Linux, Darwin
89 // x86-32 FreeBSD, Linux, Darwin
90 // PowerPC Linux
91 // ARM Darwin (*not* EABI)
92 // AArch64 Linux
93 return 32;
94}
95
96bool TargetCodeGenInfo::isNoProtoCallVariadic(const CallArgList &args,
97 const FunctionNoProtoType *fnType) const {
98 // The following conventions are known to require this to be false:
99 // x86_stdcall
100 // MIPS
101 // For everything else, we just prefer false unless we opt out.
102 return false;
103}
104
105void
106TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib,
107 llvm::SmallString<24> &Opt) const {
108 // This assumes the user is passing a library name like "rt" instead of a
109 // filename like "librt.a/so", and that they don't care whether it's static or
110 // dynamic.
111 Opt = "-l";
112 Opt += Lib;
113}
114
115unsigned TargetCodeGenInfo::getDeviceKernelCallingConv() const {
116 // Device kernels are called via an explicit runtime API with arguments,
117 // such as set with clSetKernelArg() for OpenCL, not as normal
118 // sub-functions. This uses a modified version of the C calling convention
119 // which simplifies the treatment of non-scalar types. (The rule adjustment
120 // hapens in CodeGenTypes::arrangeLLVMFunctionInfo.)
121 //
122 // Outside of OpenCL, kernels currently do not exist for CPU targets.
123 assert(getABIInfo().getContext().getLangOpts().OpenCL &&
124 "Kernel calling convention only defined for OpenCL");
125 return llvm::CallingConv::C;
126}
127
128void TargetCodeGenInfo::setOCLKernelStubCallingConvention(
129 const FunctionType *&FT) const {
130 FT = getABIInfo().getContext().adjustFunctionType(
131 Fn: FT, EInfo: FT->getExtInfo().withCallingConv(cc: CC_C));
132}
133
134llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM,
135 llvm::PointerType *T, QualType QT) const {
136 return llvm::ConstantPointerNull::get(T);
137}
138
139LangAS TargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
140 const VarDecl *D) const {
141 assert(!CGM.getLangOpts().OpenCL &&
142 !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&
143 "Address space agnostic languages only");
144 return D ? D->getType().getAddressSpace() : LangAS::Default;
145}
146
147StringRef
148TargetCodeGenInfo::getLLVMSyncScopeStr(const LangOptions &LangOpts,
149 SyncScope Scope,
150 llvm::AtomicOrdering Ordering) const {
151 return ""; /* default sync scope */
152}
153
154llvm::SyncScope::ID
155TargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &LangOpts,
156 SyncScope Scope,
157 llvm::AtomicOrdering Ordering,
158 llvm::LLVMContext &Ctx) const {
159 return Ctx.getOrInsertSyncScopeID(
160 SSN: getLLVMSyncScopeStr(LangOpts, Scope, Ordering));
161}
162
163void CodeGen::addAtomicIgnoreDenormalModeMetadata(CodeGenFunction &CGF,
164 llvm::Instruction &AtomicInst,
165 bool AllowHalf) {
166 auto *RMW = dyn_cast<llvm::AtomicRMWInst>(Val: &AtomicInst);
167 if (!RMW || RMW->getOperation() != llvm::AtomicRMWInst::FAdd)
168 return;
169
170 llvm::Type *Ty = RMW->getType();
171 if (!Ty->isFloatTy() && !(AllowHalf && Ty->isHalfTy()))
172 return;
173
174 RMW->setMetadata(KindID: llvm::LLVMContext::MD_atomic_ignore_denormal_mode,
175 Node: llvm::MDNode::get(Context&: CGF.getLLVMContext(), MDs: {}));
176}
177
178void TargetCodeGenInfo::addStackProbeTargetAttributes(
179 const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const {
180 if (llvm::Function *Fn = dyn_cast_or_null<llvm::Function>(Val: GV)) {
181 if (CGM.getCodeGenOpts().StackProbeSize != 4096)
182 Fn->addFnAttr(Kind: "stack-probe-size",
183 Val: llvm::utostr(X: CGM.getCodeGenOpts().StackProbeSize));
184 if (CGM.getCodeGenOpts().NoStackArgProbe)
185 Fn->addFnAttr(Kind: "no-stack-arg-probe");
186 }
187}
188
189/// Create an OpenCL kernel for an enqueued block.
190///
191/// The kernel has the same function type as the block invoke function. Its
192/// name is the name of the block invoke function postfixed with "_kernel".
193/// It simply calls the block invoke function then returns.
194llvm::Value *TargetCodeGenInfo::createEnqueuedBlockKernel(
195 CodeGenFunction &CGF, llvm::Function *Invoke, llvm::Type *BlockTy) const {
196 auto *InvokeFT = Invoke->getFunctionType();
197 auto &C = CGF.getLLVMContext();
198 std::string Name = Invoke->getName().str() + "_kernel";
199 auto *FT = llvm::FunctionType::get(Result: llvm::Type::getVoidTy(C),
200 Params: InvokeFT->params(), isVarArg: false);
201 auto *F = llvm::Function::Create(Ty: FT, Linkage: llvm::GlobalValue::ExternalLinkage, N: Name,
202 M: &CGF.CGM.getModule());
203 llvm::CallingConv::ID KernelCC =
204 CGF.getTypes().ClangCallConvToLLVMCallConv(CC: CallingConv::CC_DeviceKernel);
205 F->setCallingConv(KernelCC);
206
207 llvm::AttrBuilder KernelAttrs(C);
208
209 // FIXME: This is missing setTargetAttributes
210 CGF.CGM.addDefaultFunctionDefinitionAttributes(attrs&: KernelAttrs);
211 F->addFnAttrs(Attrs: KernelAttrs);
212
213 if (CGF.Builder.getIsFPConstrained())
214 F->addFnAttr(Kind: llvm::Attribute::StrictFP);
215
216 auto IP = CGF.Builder.saveIP();
217 auto *BB = llvm::BasicBlock::Create(Context&: C, Name: "entry", Parent: F);
218 auto &Builder = CGF.Builder;
219 Builder.SetInsertPoint(BB);
220 llvm::SmallVector<llvm::Value *, 2> Args(llvm::make_pointer_range(Range: F->args()));
221 llvm::CallInst *Call = Builder.CreateCall(Callee: Invoke, Args);
222 Call->setCallingConv(Invoke->getCallingConv());
223
224 Builder.CreateRetVoid();
225 Builder.restoreIP(IP);
226 return F;
227}
228
229void TargetCodeGenInfo::setBranchProtectionFnAttributes(
230 const TargetInfo::BranchProtectionInfo &BPI, llvm::Function &F) {
231 // Called on already created and initialized function where attributes already
232 // set from command line attributes but some might need to be removed as the
233 // actual BPI is different.
234
235 if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {
236 F.addFnAttr(Kind: "sign-return-address", Val: BPI.getSignReturnAddrStr());
237 F.addFnAttr(Kind: "sign-return-address-key", Val: BPI.getSignKeyStr());
238 } else {
239 if (F.hasFnAttribute(Kind: "sign-return-address"))
240 F.removeFnAttr(Kind: "sign-return-address");
241 if (F.hasFnAttribute(Kind: "sign-return-address-key"))
242 F.removeFnAttr(Kind: "sign-return-address-key");
243 }
244
245 if (BPI.SignReturnAddressHardening ==
246 LangOptions::SignReturnAddressHardeningKind::None) {
247 F.removeFnAttr(Kind: "sign-return-address-harden");
248 } else {
249 F.addFnAttr(Kind: "sign-return-address-harden",
250 Val: BPI.getSignReturnAddressHardeningStr());
251 }
252
253 auto AddRemoveAttributeAsSet = [&](bool Set, const StringRef &ModAttr) {
254 if (Set)
255 F.addFnAttr(Kind: ModAttr);
256 else if (F.hasFnAttribute(Kind: ModAttr))
257 F.removeFnAttr(Kind: ModAttr);
258 };
259
260 AddRemoveAttributeAsSet(BPI.BranchTargetEnforcement,
261 "branch-target-enforcement");
262 AddRemoveAttributeAsSet(BPI.BranchProtectionPAuthLR,
263 "branch-protection-pauth-lr");
264 AddRemoveAttributeAsSet(BPI.GuardedControlStack, "guarded-control-stack");
265}
266
267void TargetCodeGenInfo::initBranchProtectionFnAttributes(
268 const TargetInfo::BranchProtectionInfo &BPI, llvm::AttrBuilder &FuncAttrs) {
269 // Only used for initializing attributes in the AttrBuilder, which will not
270 // contain any of these attributes so no need to remove anything.
271 if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {
272 FuncAttrs.addAttribute(A: "sign-return-address", V: BPI.getSignReturnAddrStr());
273 FuncAttrs.addAttribute(A: "sign-return-address-key", V: BPI.getSignKeyStr());
274 }
275 if (BPI.SignReturnAddressHardening !=
276 LangOptions::SignReturnAddressHardeningKind::None)
277 FuncAttrs.addAttribute(A: "sign-return-address-harden",
278 V: BPI.getSignReturnAddressHardeningStr());
279 if (BPI.BranchTargetEnforcement)
280 FuncAttrs.addAttribute(A: "branch-target-enforcement");
281 if (BPI.BranchProtectionPAuthLR)
282 FuncAttrs.addAttribute(A: "branch-protection-pauth-lr");
283 if (BPI.GuardedControlStack)
284 FuncAttrs.addAttribute(A: "guarded-control-stack");
285}
286
287void TargetCodeGenInfo::setPointerAuthFnAttributes(
288 const PointerAuthOptions &Opts, llvm::Function &F) {
289 auto UpdateAttr = [&F](bool AttrShouldExist, StringRef AttrName) {
290 if (AttrShouldExist && !F.hasFnAttribute(Kind: AttrName))
291 F.addFnAttr(Kind: AttrName);
292 if (!AttrShouldExist && F.hasFnAttribute(Kind: AttrName))
293 F.removeFnAttr(Kind: AttrName);
294 };
295 UpdateAttr(Opts.ReturnAddresses, "ptrauth-returns");
296 UpdateAttr((bool)Opts.FunctionPointers, "ptrauth-calls");
297 UpdateAttr(Opts.AuthTraps, "ptrauth-auth-traps");
298 UpdateAttr(Opts.IndirectGotos, "ptrauth-indirect-gotos");
299 UpdateAttr(Opts.AArch64JumpTableHardening, "aarch64-jump-table-hardening");
300}
301
302void TargetCodeGenInfo::initPointerAuthFnAttributes(
303 const PointerAuthOptions &Opts, llvm::AttrBuilder &FuncAttrs) {
304 if (Opts.ReturnAddresses)
305 FuncAttrs.addAttribute(A: "ptrauth-returns");
306 if (Opts.FunctionPointers)
307 FuncAttrs.addAttribute(A: "ptrauth-calls");
308 if (Opts.AuthTraps)
309 FuncAttrs.addAttribute(A: "ptrauth-auth-traps");
310 if (Opts.IndirectGotos)
311 FuncAttrs.addAttribute(A: "ptrauth-indirect-gotos");
312 if (Opts.AArch64JumpTableHardening)
313 FuncAttrs.addAttribute(A: "aarch64-jump-table-hardening");
314}
315
316namespace {
317class DefaultTargetCodeGenInfo : public TargetCodeGenInfo {
318public:
319 DefaultTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
320 : TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(args&: CGT)) {}
321};
322} // namespace
323
324std::unique_ptr<TargetCodeGenInfo>
325CodeGen::createDefaultTargetCodeGenInfo(CodeGenModule &CGM) {
326 return std::make_unique<DefaultTargetCodeGenInfo>(args&: CGM.getTypes());
327}
328