1ee791ddeSRoman Divacky //===---- TargetInfo.cpp - Encapsulate target details -----------*- C++ -*-===//
2ee791ddeSRoman Divacky //
322989816SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
422989816SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
522989816SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ee791ddeSRoman Divacky //
7ee791ddeSRoman Divacky //===----------------------------------------------------------------------===//
8ee791ddeSRoman Divacky //
9ee791ddeSRoman Divacky // These classes wrap the information about a call or function
10ee791ddeSRoman Divacky // definition used to handle ABI compliancy.
11ee791ddeSRoman Divacky //
12ee791ddeSRoman Divacky //===----------------------------------------------------------------------===//
13ee791ddeSRoman Divacky
14ee791ddeSRoman Divacky #include "TargetInfo.h"
15ee791ddeSRoman Divacky #include "ABIInfo.h"
167fa27ce4SDimitry Andric #include "ABIInfoImpl.h"
17ee791ddeSRoman Divacky #include "CodeGenFunction.h"
18676fbe81SDimitry Andric #include "clang/Basic/CodeGenOptions.h"
19bfef3995SDimitry Andric #include "clang/CodeGen/CGFunctionInfo.h"
2006d4ba38SDimitry Andric #include "llvm/ADT/StringExtras.h"
21461a67faSDimitry Andric #include "llvm/ADT/Twine.h"
22ac9a064cSDimitry Andric #include "llvm/IR/Function.h"
23809500fcSDimitry Andric #include "llvm/IR/Type.h"
24ee791ddeSRoman Divacky #include "llvm/Support/raw_ostream.h"
259f4dbff6SDimitry Andric
26ee791ddeSRoman Divacky using namespace clang;
27ee791ddeSRoman Divacky using namespace CodeGen;
28ee791ddeSRoman Divacky
dump() const292b6b257fSDimitry Andric LLVM_DUMP_METHOD void ABIArgInfo::dump() const {
3036981b17SDimitry Andric raw_ostream &OS = llvm::errs();
31ee791ddeSRoman Divacky OS << "(ABIArgInfo Kind=";
32ee791ddeSRoman Divacky switch (TheKind) {
33ee791ddeSRoman Divacky case Direct:
343d1dcd9bSDimitry Andric OS << "Direct Type=";
3536981b17SDimitry Andric if (llvm::Type *Ty = getCoerceToType())
363d1dcd9bSDimitry Andric Ty->print(OS);
373d1dcd9bSDimitry Andric else
383d1dcd9bSDimitry Andric OS << "null";
39ee791ddeSRoman Divacky break;
40ee791ddeSRoman Divacky case Extend:
41ee791ddeSRoman Divacky OS << "Extend";
42ee791ddeSRoman Divacky break;
43ee791ddeSRoman Divacky case Ignore:
44ee791ddeSRoman Divacky OS << "Ignore";
45ee791ddeSRoman Divacky break;
469f4dbff6SDimitry Andric case InAlloca:
479f4dbff6SDimitry Andric OS << "InAlloca Offset=" << getInAllocaFieldIndex();
489f4dbff6SDimitry Andric break;
49ee791ddeSRoman Divacky case Indirect:
5045b53394SDimitry Andric OS << "Indirect Align=" << getIndirectAlign().getQuantity()
51180abc3dSDimitry Andric << " ByVal=" << getIndirectByVal()
52bca07a45SDimitry Andric << " Realign=" << getIndirectRealign();
53ee791ddeSRoman Divacky break;
54b60736ecSDimitry Andric case IndirectAliased:
55b60736ecSDimitry Andric OS << "Indirect Align=" << getIndirectAlign().getQuantity()
56b60736ecSDimitry Andric << " AadrSpace=" << getIndirectAddrSpace()
57b60736ecSDimitry Andric << " Realign=" << getIndirectRealign();
58b60736ecSDimitry Andric break;
59ee791ddeSRoman Divacky case Expand:
60ee791ddeSRoman Divacky OS << "Expand";
61ee791ddeSRoman Divacky break;
622b6b257fSDimitry Andric case CoerceAndExpand:
632b6b257fSDimitry Andric OS << "CoerceAndExpand Type=";
642b6b257fSDimitry Andric getCoerceAndExpandType()->print(OS);
652b6b257fSDimitry Andric break;
66ee791ddeSRoman Divacky }
67ee791ddeSRoman Divacky OS << ")\n";
68ee791ddeSRoman Divacky }
69ee791ddeSRoman Divacky
TargetCodeGenInfo(std::unique_ptr<ABIInfo> Info)704b4fe385SDimitry Andric TargetCodeGenInfo::TargetCodeGenInfo(std::unique_ptr<ABIInfo> Info)
714b4fe385SDimitry Andric : Info(std::move(Info)) {}
724b4fe385SDimitry Andric
73cfca06d7SDimitry Andric TargetCodeGenInfo::~TargetCodeGenInfo() = default;
74ee791ddeSRoman Divacky
7536981b17SDimitry Andric // If someone can figure out a general rule for this, that would be great.
7636981b17SDimitry Andric // It's probably just doomed to be platform-dependent, though.
getSizeOfUnwindException() const7736981b17SDimitry Andric unsigned TargetCodeGenInfo::getSizeOfUnwindException() const {
7836981b17SDimitry Andric // Verified for:
7936981b17SDimitry Andric // x86-64 FreeBSD, Linux, Darwin
8036981b17SDimitry Andric // x86-32 FreeBSD, Linux, Darwin
817fa27ce4SDimitry Andric // PowerPC Linux
8236981b17SDimitry Andric // ARM Darwin (*not* EABI)
83809500fcSDimitry Andric // AArch64 Linux
8436981b17SDimitry Andric return 32;
8536981b17SDimitry Andric }
8636981b17SDimitry Andric
isNoProtoCallVariadic(const CallArgList & args,const FunctionNoProtoType * fnType) const87dbe13110SDimitry Andric bool TargetCodeGenInfo::isNoProtoCallVariadic(const CallArgList &args,
88dbe13110SDimitry Andric const FunctionNoProtoType *fnType) const {
8936981b17SDimitry Andric // The following conventions are known to require this to be false:
9036981b17SDimitry Andric // x86_stdcall
9136981b17SDimitry Andric // MIPS
9236981b17SDimitry Andric // For everything else, we just prefer false unless we opt out.
9336981b17SDimitry Andric return false;
9436981b17SDimitry Andric }
9536981b17SDimitry Andric
96bfef3995SDimitry Andric void
getDependentLibraryOption(llvm::StringRef Lib,llvm::SmallString<24> & Opt) const97bfef3995SDimitry Andric TargetCodeGenInfo::getDependentLibraryOption(llvm::StringRef Lib,
98bfef3995SDimitry Andric llvm::SmallString<24> &Opt) const {
99bfef3995SDimitry Andric // This assumes the user is passing a library name like "rt" instead of a
100bfef3995SDimitry Andric // filename like "librt.a/so", and that they don't care whether it's static or
101bfef3995SDimitry Andric // dynamic.
102bfef3995SDimitry Andric Opt = "-l";
103bfef3995SDimitry Andric Opt += Lib;
104bfef3995SDimitry Andric }
105bfef3995SDimitry Andric
getOpenCLKernelCallingConv() const1062b6b257fSDimitry Andric unsigned TargetCodeGenInfo::getOpenCLKernelCallingConv() const {
107416ada0fSDimitry Andric // OpenCL kernels are called via an explicit runtime API with arguments
108416ada0fSDimitry Andric // set with clSetKernelArg(), not as normal sub-functions.
109416ada0fSDimitry Andric // Return SPIR_KERNEL by default as the kernel calling convention to
110416ada0fSDimitry Andric // ensure the fingerprint is fixed such way that each OpenCL argument
111416ada0fSDimitry Andric // gets one matching argument in the produced kernel function argument
112416ada0fSDimitry Andric // list to enable feasible implementation of clSetKernelArg() with
113416ada0fSDimitry Andric // aggregates etc. In case we would use the default C calling conv here,
114416ada0fSDimitry Andric // clSetKernelArg() might break depending on the target-specific
115416ada0fSDimitry Andric // conventions; different targets might split structs passed as values
116416ada0fSDimitry Andric // to multiple function arguments etc.
117416ada0fSDimitry Andric return llvm::CallingConv::SPIR_KERNEL;
1182b6b257fSDimitry Andric }
119bab175ecSDimitry Andric
getNullPointer(const CodeGen::CodeGenModule & CGM,llvm::PointerType * T,QualType QT) const120bab175ecSDimitry Andric llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM,
121bab175ecSDimitry Andric llvm::PointerType *T, QualType QT) const {
122bab175ecSDimitry Andric return llvm::ConstantPointerNull::get(T);
123bab175ecSDimitry Andric }
124bab175ecSDimitry Andric
getGlobalVarAddressSpace(CodeGenModule & CGM,const VarDecl * D) const125461a67faSDimitry Andric LangAS TargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM,
1268746d127SDimitry Andric const VarDecl *D) const {
1278746d127SDimitry Andric assert(!CGM.getLangOpts().OpenCL &&
1288746d127SDimitry Andric !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) &&
1298746d127SDimitry Andric "Address space agnostic languages only");
130461a67faSDimitry Andric return D ? D->getType().getAddressSpace() : LangAS::Default;
1318746d127SDimitry Andric }
1328746d127SDimitry Andric
performAddrSpaceCast(CodeGen::CodeGenFunction & CGF,llvm::Value * Src,LangAS SrcAddr,LangAS DestAddr,llvm::Type * DestTy,bool isNonNull) const133bab175ecSDimitry Andric llvm::Value *TargetCodeGenInfo::performAddrSpaceCast(
134461a67faSDimitry Andric CodeGen::CodeGenFunction &CGF, llvm::Value *Src, LangAS SrcAddr,
135461a67faSDimitry Andric LangAS DestAddr, llvm::Type *DestTy, bool isNonNull) const {
136bab175ecSDimitry Andric // Since target may map different address spaces in AST to the same address
137bab175ecSDimitry Andric // space, an address space conversion may end up as a bitcast.
1388746d127SDimitry Andric if (auto *C = dyn_cast<llvm::Constant>(Src))
1398746d127SDimitry Andric return performAddrSpaceCast(CGF.CGM, C, SrcAddr, DestAddr, DestTy);
14022989816SDimitry Andric // Try to preserve the source's name to make IR more readable.
141b1c73532SDimitry Andric return CGF.Builder.CreateAddrSpaceCast(
14222989816SDimitry Andric Src, DestTy, Src->hasName() ? Src->getName() + ".ascast" : "");
143bab175ecSDimitry Andric }
144bab175ecSDimitry Andric
1458746d127SDimitry Andric llvm::Constant *
performAddrSpaceCast(CodeGenModule & CGM,llvm::Constant * Src,LangAS SrcAddr,LangAS DestAddr,llvm::Type * DestTy) const1468746d127SDimitry Andric TargetCodeGenInfo::performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *Src,
147461a67faSDimitry Andric LangAS SrcAddr, LangAS DestAddr,
1488746d127SDimitry Andric llvm::Type *DestTy) const {
1498746d127SDimitry Andric // Since target may map different address spaces in AST to the same address
1508746d127SDimitry Andric // space, an address space conversion may end up as a bitcast.
1518746d127SDimitry Andric return llvm::ConstantExpr::getPointerCast(Src, DestTy);
1528746d127SDimitry Andric }
1538746d127SDimitry Andric
154461a67faSDimitry Andric llvm::SyncScope::ID
getLLVMSyncScopeID(const LangOptions & LangOpts,SyncScope Scope,llvm::AtomicOrdering Ordering,llvm::LLVMContext & Ctx) const15522989816SDimitry Andric TargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &LangOpts,
15622989816SDimitry Andric SyncScope Scope,
15722989816SDimitry Andric llvm::AtomicOrdering Ordering,
15822989816SDimitry Andric llvm::LLVMContext &Ctx) const {
15922989816SDimitry Andric return Ctx.getOrInsertSyncScopeID(""); /* default sync scope */
160461a67faSDimitry Andric }
161461a67faSDimitry Andric
addStackProbeTargetAttributes(const Decl * D,llvm::GlobalValue * GV,CodeGen::CodeGenModule & CGM) const1627fa27ce4SDimitry Andric void TargetCodeGenInfo::addStackProbeTargetAttributes(
16348675466SDimitry Andric const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const {
16448675466SDimitry Andric if (llvm::Function *Fn = dyn_cast_or_null<llvm::Function>(GV)) {
16548675466SDimitry Andric if (CGM.getCodeGenOpts().StackProbeSize != 4096)
166798321d8SDimitry Andric Fn->addFnAttr("stack-probe-size",
167798321d8SDimitry Andric llvm::utostr(CGM.getCodeGenOpts().StackProbeSize));
16848675466SDimitry Andric if (CGM.getCodeGenOpts().NoStackArgProbe)
16948675466SDimitry Andric Fn->addFnAttr("no-stack-arg-probe");
1705e20cdd8SDimitry Andric }
1715e20cdd8SDimitry Andric }
1725e20cdd8SDimitry Andric
173461a67faSDimitry Andric /// Create an OpenCL kernel for an enqueued block.
174461a67faSDimitry Andric ///
175461a67faSDimitry Andric /// The kernel has the same function type as the block invoke function. Its
176461a67faSDimitry Andric /// name is the name of the block invoke function postfixed with "_kernel".
177461a67faSDimitry Andric /// It simply calls the block invoke function then returns.
createEnqueuedBlockKernel(CodeGenFunction & CGF,llvm::Function * Invoke,llvm::Type * BlockTy) const1787fa27ce4SDimitry Andric llvm::Value *TargetCodeGenInfo::createEnqueuedBlockKernel(
1797fa27ce4SDimitry Andric CodeGenFunction &CGF, llvm::Function *Invoke, llvm::Type *BlockTy) const {
180461a67faSDimitry Andric auto *InvokeFT = Invoke->getFunctionType();
181461a67faSDimitry Andric auto &C = CGF.getLLVMContext();
182461a67faSDimitry Andric std::string Name = Invoke->getName().str() + "_kernel";
183145449b1SDimitry Andric auto *FT = llvm::FunctionType::get(llvm::Type::getVoidTy(C),
184145449b1SDimitry Andric InvokeFT->params(), false);
1856f8fc217SDimitry Andric auto *F = llvm::Function::Create(FT, llvm::GlobalValue::ExternalLinkage, Name,
186461a67faSDimitry Andric &CGF.CGM.getModule());
1877fa27ce4SDimitry Andric llvm::CallingConv::ID KernelCC =
1887fa27ce4SDimitry Andric CGF.getTypes().ClangCallConvToLLVMCallConv(CallingConv::CC_OpenCLKernel);
1897fa27ce4SDimitry Andric F->setCallingConv(KernelCC);
1907fa27ce4SDimitry Andric
1917fa27ce4SDimitry Andric llvm::AttrBuilder KernelAttrs(C);
1927fa27ce4SDimitry Andric
1937fa27ce4SDimitry Andric // FIXME: This is missing setTargetAttributes
1947fa27ce4SDimitry Andric CGF.CGM.addDefaultFunctionDefinitionAttributes(KernelAttrs);
1957fa27ce4SDimitry Andric F->addFnAttrs(KernelAttrs);
1967fa27ce4SDimitry Andric
197461a67faSDimitry Andric auto IP = CGF.Builder.saveIP();
198461a67faSDimitry Andric auto *BB = llvm::BasicBlock::Create(C, "entry", F);
199461a67faSDimitry Andric auto &Builder = CGF.Builder;
200461a67faSDimitry Andric Builder.SetInsertPoint(BB);
201145449b1SDimitry Andric llvm::SmallVector<llvm::Value *, 2> Args(llvm::make_pointer_range(F->args()));
2027fa27ce4SDimitry Andric llvm::CallInst *Call = Builder.CreateCall(Invoke, Args);
2037fa27ce4SDimitry Andric Call->setCallingConv(Invoke->getCallingConv());
2047fa27ce4SDimitry Andric
205461a67faSDimitry Andric Builder.CreateRetVoid();
206461a67faSDimitry Andric Builder.restoreIP(IP);
207461a67faSDimitry Andric return F;
208461a67faSDimitry Andric }
209461a67faSDimitry Andric
setBranchProtectionFnAttributes(const TargetInfo::BranchProtectionInfo & BPI,llvm::Function & F)210ac9a064cSDimitry Andric void TargetCodeGenInfo::setBranchProtectionFnAttributes(
211ac9a064cSDimitry Andric const TargetInfo::BranchProtectionInfo &BPI, llvm::Function &F) {
212adf62863SDimitry Andric // Called on already created and initialized function where attributes already
213adf62863SDimitry Andric // set from command line attributes but some might need to be removed as the
214adf62863SDimitry Andric // actual BPI is different.
215adf62863SDimitry Andric if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {
216adf62863SDimitry Andric F.addFnAttr("sign-return-address", BPI.getSignReturnAddrStr());
217adf62863SDimitry Andric F.addFnAttr("sign-return-address-key", BPI.getSignKeyStr());
218adf62863SDimitry Andric } else {
219adf62863SDimitry Andric if (F.hasFnAttribute("sign-return-address"))
220adf62863SDimitry Andric F.removeFnAttr("sign-return-address");
221adf62863SDimitry Andric if (F.hasFnAttribute("sign-return-address-key"))
222adf62863SDimitry Andric F.removeFnAttr("sign-return-address-key");
223ac9a064cSDimitry Andric }
224ac9a064cSDimitry Andric
225adf62863SDimitry Andric auto AddRemoveAttributeAsSet = [&](bool Set, const StringRef &ModAttr) {
226adf62863SDimitry Andric if (Set)
227adf62863SDimitry Andric F.addFnAttr(ModAttr);
228adf62863SDimitry Andric else if (F.hasFnAttribute(ModAttr))
229adf62863SDimitry Andric F.removeFnAttr(ModAttr);
230adf62863SDimitry Andric };
231adf62863SDimitry Andric
232adf62863SDimitry Andric AddRemoveAttributeAsSet(BPI.BranchTargetEnforcement,
233adf62863SDimitry Andric "branch-target-enforcement");
234adf62863SDimitry Andric AddRemoveAttributeAsSet(BPI.BranchProtectionPAuthLR,
235adf62863SDimitry Andric "branch-protection-pauth-lr");
236adf62863SDimitry Andric AddRemoveAttributeAsSet(BPI.GuardedControlStack, "guarded-control-stack");
237adf62863SDimitry Andric }
238adf62863SDimitry Andric
initBranchProtectionFnAttributes(const TargetInfo::BranchProtectionInfo & BPI,llvm::AttrBuilder & FuncAttrs)239adf62863SDimitry Andric void TargetCodeGenInfo::initBranchProtectionFnAttributes(
240ac9a064cSDimitry Andric const TargetInfo::BranchProtectionInfo &BPI, llvm::AttrBuilder &FuncAttrs) {
241adf62863SDimitry Andric // Only used for initializing attributes in the AttrBuilder, which will not
242adf62863SDimitry Andric // contain any of these attributes so no need to remove anything.
243ac9a064cSDimitry Andric if (BPI.SignReturnAddr != LangOptions::SignReturnAddressScopeKind::None) {
244ac9a064cSDimitry Andric FuncAttrs.addAttribute("sign-return-address", BPI.getSignReturnAddrStr());
245ac9a064cSDimitry Andric FuncAttrs.addAttribute("sign-return-address-key", BPI.getSignKeyStr());
246ac9a064cSDimitry Andric }
247ac9a064cSDimitry Andric if (BPI.BranchTargetEnforcement)
248ac9a064cSDimitry Andric FuncAttrs.addAttribute("branch-target-enforcement");
249ac9a064cSDimitry Andric if (BPI.BranchProtectionPAuthLR)
250ac9a064cSDimitry Andric FuncAttrs.addAttribute("branch-protection-pauth-lr");
251ac9a064cSDimitry Andric if (BPI.GuardedControlStack)
252ac9a064cSDimitry Andric FuncAttrs.addAttribute("guarded-control-stack");
253ac9a064cSDimitry Andric }
254ac9a064cSDimitry Andric
2557fa27ce4SDimitry Andric namespace {
2567fa27ce4SDimitry Andric class DefaultTargetCodeGenInfo : public TargetCodeGenInfo {
2577fa27ce4SDimitry Andric public:
DefaultTargetCodeGenInfo(CodeGen::CodeGenTypes & CGT)2587fa27ce4SDimitry Andric DefaultTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT)
2597fa27ce4SDimitry Andric : TargetCodeGenInfo(std::make_unique<DefaultABIInfo>(CGT)) {}
2607fa27ce4SDimitry Andric };
2617fa27ce4SDimitry Andric } // namespace
262461a67faSDimitry Andric
2637fa27ce4SDimitry Andric std::unique_ptr<TargetCodeGenInfo>
createDefaultTargetCodeGenInfo(CodeGenModule & CGM)2647fa27ce4SDimitry Andric CodeGen::createDefaultTargetCodeGenInfo(CodeGenModule &CGM) {
2657fa27ce4SDimitry Andric return std::make_unique<DefaultTargetCodeGenInfo>(CGM.getTypes());
266461a67faSDimitry Andric }
267