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